diff --git a/.editorconfig b/.editorconfig
index d9c3abd5..d72a75ea 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,29 +1,25 @@
-# EditorConfig helps developers define and maintain consistent
-# coding styles between different editors and IDEs
-# http://editorconfig.org
-# 所有文件换行使用 Unix like 风格(LF),bat 文件使用 win 风格(CRLF)
-# 缩进 java 4 个空格,其他所有文件 2 个空格
+# EditorConfig 用于在 IDE 中检查代码的基本 Code Style
+# @see: https://editorconfig.org/
+
+# 配置说明:
+# 所有文件换行使用 Unix 风格(LF),*.bat 文件使用 Windows 风格(CRLF)
+# java / sh 文件缩进 4 个空格,其他所有文件缩进 2 个空格
root = true
[*]
-# Unix-style newlines with a newline ending every file
end_of_line = lf
-
-# Change these settings to your own preference
indent_size = 2
indent_style = space
max_line_length = 120
-
-# We recommend you to keep these unchanged
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
-[*.bat]
+[*.{bat, cmd}]
end_of_line = crlf
-[*.java]
+[*.{java, gradle, groovy, kt, sh}]
indent_size = 4
[*.md]
diff --git a/.gitattributes b/.gitattributes
index 1e3aabc2..07962a1f 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -70,6 +70,8 @@
*.pdf binary
*.doc binary
*.docx binary
+*.ppt binary
+*.pptx binary
*.xls binary
*.xlsx binary
*.xmind binary
diff --git a/.gitignore b/.gitignore
index a684e5ed..e3e2b4c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,43 @@
-################ JAVASCRIPT ################
+# ---------------------------------------------------------------------
+# more gitignore templates see https://github.com/github/gitignore
+# ---------------------------------------------------------------------
+
+# ------------------------------- java -------------------------------
+# compiled folders
+classes
+target
+logs
+.mtj.tmp/
+
+# compiled files
+*.class
+
+# bluej files
+*.ctxt
+
+# package files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs
+hs_err_pid*
+
+# maven plugin temp files
+.flattened-pom.xml
+package-lock.json
+pnpm-lock.yaml
+
+# ------------------------------- javascript -------------------------------
# dependencies
node_modules
# temp folders
+.temp
dist
_book
_jsdoc
@@ -13,13 +48,12 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
bundle*.js
+book.pdf
-
-################ IDEA ################
+# ------------------------------- intellij -------------------------------
.idea
*.iml
-
-################ Eclipse ################
+# ------------------------------- eclipse -------------------------------
.classpath
.project
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..47463f91
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,24 @@
+# 持续集成 CI
+# @see https://docs.travis-ci.com/user/tutorial/
+
+language: node_js
+
+sudo: required
+
+node_js: '16.13.0'
+
+branches:
+ only:
+ - master
+
+before_install:
+ - export TZ=Asia/Shanghai
+
+script: bash ./scripts/deploy.sh
+
+notifications:
+ email:
+ recipients:
+ - forbreak@163.com
+ on_success: change
+ on_failure: always
diff --git a/LICENSE b/LICENSE
index 6a8657f1..3b7b82d0 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,427 @@
-MIT License
-
-Copyright (c) 2018 Zhang Peng
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+Attribution-ShareAlike 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+ Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+ wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More_considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-ShareAlike 4.0 International Public
+License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-ShareAlike 4.0 International Public License ("Public
+License"). To the extent this Public License may be interpreted as a
+contract, You are granted the Licensed Rights in consideration of Your
+acceptance of these terms and conditions, and the Licensor grants You
+such rights in consideration of benefits the Licensor receives from
+making the Licensed Material available under these terms and
+conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material in
+ accordance with the terms and conditions of this Public License.
+
+ c. BY-SA Compatible License means a license listed at
+ creativecommons.org/compatiblelicenses, approved by Creative
+ Commons as essentially the equivalent of this Public License.
+
+ d. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ e. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ f. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ g. License Elements means the license attributes listed in the name
+ of a Creative Commons Public License. The License Elements of this
+ Public License are Attribution and ShareAlike.
+
+ h. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ i. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ j. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ k. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ l. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ m. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part; and
+
+ b. produce, reproduce, and Share Adapted Material.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. Additional offer from the Licensor -- Adapted Material.
+ Every recipient of Adapted Material from You
+ automatically receives an offer from the Licensor to
+ exercise the Licensed Rights in the Adapted Material
+ under the conditions of the Adapter's License You apply.
+
+ c. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+ b. ShareAlike.
+
+ In addition to the conditions in Section 3(a), if You Share
+ Adapted Material You produce, the following conditions also apply.
+
+ 1. The Adapter's License You apply must be a Creative Commons
+ license with the same License Elements, this version or
+ later, or a BY-SA Compatible License.
+
+ 2. You must include the text of, or the URI or hyperlink to, the
+ Adapter's License You apply. You may satisfy this condition
+ in any reasonable manner based on the medium, means, and
+ context in which You Share Adapted Material.
+
+ 3. You may not offer or impose any additional or different terms
+ or conditions on, or apply any Effective Technological
+ Measures to, Adapted Material that restrict exercise of the
+ rights granted under the Adapter's License You apply.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material,
+
+ including for purposes of Section 3(b); and
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the “Licensor.” The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/README.md b/README.md
index 6963a22b..b5e9a3de 100644
--- a/README.md
+++ b/README.md
@@ -1,105 +1,128 @@
-# Linux 教程
+
+
+
+
+
-> :keyboard: 项目同步维护在 [github](https://github.com/dunwu/linux-tutorial) | [gitee](https://gitee.com/turnon/linux-tutorial)
+
+
+
+
+
+linux-tutorial
+
+> 📚 **linux-tutorial** 是一个 Linux 教程。
>
-> :book: [电子书](https://dunwu.github.io/linux-tutorial/) | [电子书(国内)](http://turnon.gitee.io/linux-tutorial/)
+> - 🔁 项目同步维护:[Github](https://github.com/dunwu/linux-tutorial/) | [Gitee](https://gitee.com/turnon/linux-tutorial/)
+> - 📖 电子书阅读:[Github Pages](https://dunwu.github.io/linux-tutorial/) | [Gitee Pages](http://turnon.gitee.io/linux-tutorial/)
+
+## 📖 内容
+
+### Linux 命令
+
+> 学习 Linux 的第一步:当然是从 [Linux 命令](docs/linux/cli/README.md) 入手了。
-| :wrench: | :shell: | :memo: | :books: |
-| :-------------------: | :-------------------: | :---------------: | :-------------------: |
-| [软件运维](#软件运维) | [运维脚本](#运维脚本) | [知识点](#知识点) | [学习资源](#学习资源) |
+- [查看 Linux 命令帮助信息](docs/linux/cli/linux-cli-help.md) - 关键词:`help`, `whatis`, `info`, `which`, `whereis`, `man`
+- [Linux 文件目录管理](docs/linux/cli/linux-cli-dir.md) - 关键词:`cd`, `ls`, `pwd`, `mkdir`, `rmdir`, `tree`, `touch`, `ln`, `rename`, `stat`, `file`, `chmod`, `chown`, `locate`, `find`, `cp`, `mv`, `rm`
+- [Linux 文件内容查看命令](docs/linux/cli/linux-cli-file.md) - 关键词:`cat`, `head`, `tail`, `more`, `less`, `sed`, `vi`, `grep`
+- [Linux 文件压缩和解压](docs/linux/cli/linux-cli-file-compress.md) - 关键词:`tar`, `gzip`, `zip`, `unzip`
+- [Linux 用户管理](docs/linux/cli/linux-cli-user.md) - 关键词:`groupadd`, `groupdel`, `groupmod`, `useradd`, `userdel`, `usermod`, `passwd`, `su`, `sudo`
+- [Linux 系统管理](docs/linux/cli/linux-cli-system.md) - 关键词:`reboot`, `exit`, `shutdown`, `date`, `mount`, `umount`, `ps`, `kill`, `systemctl`, `service`, `crontab`
+- [Linux 网络管理](docs/linux/cli/linux-cli-net.md) - 关键词:关键词:`curl`, `wget`, `telnet`, `ip`, `hostname`, `ifconfig`, `route`, `ssh`, `ssh-keygen`, `firewalld`, `iptables`, `host`, `nslookup`, `nc`/`netcat`, `ping`, `traceroute`, `netstat`
+- [Linux 硬件管理](docs/linux/cli/linux-cli-hardware.md) - 关键词:`df`, `du`, `top`, `free`, `iotop`
+- [Linux 软件管理](docs/linux/cli/linux-cli-software.md) - 关键词:`rpm`, `yum`, `apt-get`
-## 软件运维
+### Linux 运维
-> 本章节内容介绍日常开发中常见的一些软件、工具的安装、配置。
+> Linux 系统的常见运维工作。
+
+- [网络运维](docs/linux/ops/network-ops.md)
+- [Samba](docs/linux/ops/samba.md)
+- [NTP](docs/linux/ops/ntp.md)
+- [Firewalld](docs/linux/ops/firewalld.md)
+- [Crontab](docs/linux/ops/crontab.md)
+- [Systemd](docs/linux/ops/systemd.md)
+- [Vim](docs/linux/ops/vim.md)
+- [Iptables](docs/linux/ops/iptables.md)
+- [oh-my-zsh](docs/linux/ops/zsh.md)
+
+### 软件运维
+
+> 部署在 Linux 系统上的软件运维。
+>
+> 配套安装脚本:⌨ [软件运维配置脚本集合](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft)
- 开发环境
- [JDK 安装](docs/linux/soft/jdk-install.md)
- [Maven 安装](docs/linux/soft/maven-install.md)
- [Nodejs 安装](docs/linux/soft/nodejs-install.md)
- 开发工具
- - [Nexus 运维](docs/linux/soft/nexus-install.md)
- - [Gitlab 运维](docs/linux/soft/kafka-install.md)
- - [Jenkins 运维](docs/linux/soft/jenkins.md)
+ - [Nexus 运维](docs/linux/soft/nexus-ops.md)
+ - [Gitlab 运维](docs/linux/soft/gitlab-ops.md)
+ - [Jenkins 运维](docs/linux/soft/jenkins-ops.md)
- [Svn 运维](docs/linux/soft/svn-ops.md)
- [YApi 运维](docs/linux/soft/yapi-ops.md)
- 中间件服务
- [Elastic 运维](docs/linux/soft/elastic)
- [Kafka 运维](docs/linux/soft/kafka-install.md)
- [RocketMQ 运维](docs/linux/soft/rocketmq-install.md)
- - [Zookeeper 运维](docs/linux/soft/zookeeper-install.md)
+ - [Zookeeper 运维](https://github.com/dunwu/javatech/blob/master/docs/technology/monitor/zookeeper-ops.md)
- [Nacos 运维](docs/linux/soft/nacos-install.md)
- 服务器
- - [Nginx 教程](https://github.com/dunwu/nginx-tutorial)
+ - [Nginx 教程](https://github.com/dunwu/nginx-tutorial) 📚
- [Tomcat 运维](docs/linux/soft/tomcat-install.md)
-- 数据库
- - [Mongodb 运维](docs/linux/soft/mongodb-ops.md)
- - [Redis 运维](docs/linux/soft/redis-ops.md)
-
-## 运维脚本
-
-- [系统运维脚本集合](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/sys)
-- [软件运维配置脚本集合](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft)
-- [工具脚本集合](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft)
-- [Vim 应用指南](docs/linux/ops/vim.md)
-- [Zsh 应用指南](docs/linux/ops/zsh.md)
-- [Shell 教程](docs/linux/ops/shell.md)
-- [Python 教程](docs/linux/ops/python.md)
-
-> 提供一键式运维、配置软件脚本
-
-## 知识点
-
-### Linux
-
-- [Linux 命令教程](docs/linux/cli/README.md)
- - [查看 Linux 命令帮助信息](docs/linux/cli/查看Linux命令帮助信息.md)
- - [Linux 文件目录管理](docs/linux/cli/Linux文件目录管理.md)
- - [Linux 文件内容查看命令](docs/linux/cli/Linux文件内容查看编辑.md)
- - [Linux 文件压缩和解压](docs/linux/cli/Linux文件压缩和解压.md)
- - [Linux 用户管理](docs/linux/cli/Linux用户管理.md)
- - [Linux 系统管理](docs/linux/cli/Linux系统管理.md)
- - [Linux 网络管理](docs/linux/cli/Linux网络管理.md)
- - [Linux 硬件管理](docs/linux/cli/Linux硬件管理.md)
- - [Linux 软件管理](docs/linux/cli/Linux硬件管理.md)
-- [Linux 运维](docs/linux/ops/README.md)
- - [linux 典型运维应用](docs/linux/ops/linux典型运维应用.md)
- - [samba 使用详解](docs/linux/ops/samba使用详解.md)
+- [数据库](https://github.com/dunwu/db-tutorial) 📚
+ - [Mysql 运维](https://github.com/dunwu/db-tutorial/blob/master/docs/sql/mysql/mysql-ops.md)
+ - [Redis 运维](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-ops.md)
### Docker
-- [Docker 教程](docs/docker)
- - [Docker 应用指南](docs/docker/docker.md)
- - [Docker Cheat Sheet](docs/docker/docker-cheat-sheet.md)
+- [Docker 快速入门](docs/docker/docker-quickstart.md)
+- [Dockerfile 最佳实践](docs/docker/docker-dockerfile.md)
+- [Docker Cheat Sheet](docs/docker/docker-cheat-sheet.md)
+- [Kubernetes 应用指南](docs/docker/kubernetes.md)
-### Git
+### 其他
-- [Git 教程](docs/git/README.md)
- - [Git 快速指南](docs/git/git-quickstart.md)
- - [Git 配置](docs/git/git-configuration.md)
- - [git-flow 工作流](docs/git/git-flow.md)
- - [Git 常见问题](docs/git/git-faq.md)
+- [一篇文章让你彻底掌握 Python](https://dunwu.github.io/blog/pages/ef501b/)
+- [一篇文章让你彻底掌握 Shell](https://dunwu.github.io/blog/pages/ea6ae1/)
+- [如何优雅的玩转 Git](https://dunwu.github.io/blog/pages/2fc8b1/)
-## 学习资源
+## ⌨ 脚本
-- 命令行检索
- - [Linux 命令大全](http://man.linuxde.net/)
- - [linux-command](https://jaywcjlove.gitee.io/linux-command/)
-- 社区网站
+### Shell 脚本大全
+
+**Shell 脚本大全** 精心收集、整理了 Linux 环境下的常见 Shell 脚本操作片段。
+
+源码:[**Shell 脚本大全**](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell)
+
+### CentOS 运维脚本集合
+
+本人作为一名 Java 后端,苦于经常在 CentOS 环境上开荒虚拟机。为提高效率,写了一套 Shell 脚本,提供如下功能:安装常用 lib 库、命令工具、设置 DNS、NTP、配置国内 yum 源、一键安装常用软件等。
+
+源码:[**CentOS 常规操作运维脚本集合**](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux)
+
+## 📚 资料
+
+- **Linux 命令**
+ - [命令行的艺术](https://github.com/jlevy/the-art-of-command-line/blob/master/README-zh.md)
+ - [Linux 命令大全](https://man.linuxde.net/)
+ - [linux-command](https://github.com/jaywcjlove/linux-command)
+- **社区网站**
- [Linux 中国](https://linux.cn/) - 各种资讯、文章、技术
- - [实验楼](https://www.shiyanlou.com/) - 免费提供了 Linux 在线环境,不用在自己机子上装系统也可以学习 Linux,超方便实用。
+ - [LabEx 中国](https://labex.io/) - 免费提供了 Linux 在线环境,不用在自己机子上装系统也可以学习 Linux,超方便实用。
- [鸟哥的 linux 私房菜](http://linux.vbird.org/) - 非常适合 Linux 入门初学者看的教程。
- [Linux 公社](http://www.linuxidc.com/) - Linux 相关的新闻、教程、主题、壁纸都有。
- [Linux Today](http://www.linuxde.net) - Linux 新闻资讯发布,Linux 职业技术学习!。
-- 知识相关
+- **知识相关**
- [Linux 思维导图整理](http://www.jianshu.com/p/59f759207862)
- [Linux 初学者进阶学习资源整理](http://www.jianshu.com/p/fe2a790b41eb)
- - [Linux 基础入门(新版)](https://www.shiyanlou.com/courses/1)
+ - [Linux 快速入门(动手实验)](https://labex.io/zh/courses/quick-start-with-linux)
- [【译】Linux 概念架构的理解](http://www.jianshu.com/p/c5ae8f061cfe) [En](http://oss.org.cn/ossdocs/linux/kernel/a1/index.html)
- [Linux 守护进程的启动方法](http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html)
- - [Linux 编程之内存映射](https://www.shiyanlou.com/questions/2992)
- [Linux 知识点小结](https://blog.huachao.me/2016/1/Linux%E7%9F%A5%E8%AF%86%E7%82%B9%E5%B0%8F%E7%BB%93/)
- [10 大白帽黑客专用的 Linux 操作系统](https://linux.cn/article-6971-1.html)
-- 软件工具
+- **软件工具**
- [超赞的 Linux 软件](https://www.gitbook.com/book/alim0x/awesome-linux-software-zh_cn/details) Github 仓库[Zh](https://github.com/alim0x/Awesome-Linux-Software-zh_CN) [En](https://github.com/VoLuong/Awesome-Linux-Software)
- [程序员喜欢的 9 款最佳的 Linux 文件比较工具](http://os.51cto.com/art/201607/513796.htm)
- [提高 Linux 开发效率的 5 个工具](http://www.codeceo.com/article/5-linux-productivity-tools.html)
@@ -114,7 +137,7 @@
- [Webflow (Adobe Muse)](https://webflow.com/) 一款可以帮助用户不用编码就可以快速创建网站的谷歌浏览器插件。
- [Tupi (Adobe Animate)](http://www.maefloresta.com/portal/) 一款可以创建 HTML5 动画的工具。
- [Black Magic Fusion (Adobe After Effects)](https://www.blackmagicdesign.com) 一款先进的合成软件,广泛应用于视觉特效、广电影视设计以及 3D 动画设计等领域。
-- 中国开源镜像站点
+- **中国开源镜像**
- [阿里云开源镜像站](http://mirrors.aliyun.com/)
- [网易开源镜像站](http://mirrors.163.com/)
- [搜狐开源镜像站](http://mirrors.sohu.com/)
@@ -127,3 +150,8 @@
- [东北大学](http://mirror.neu.edu.cn/)
- [浙江大学](http://mirrors.zju.edu.cn/)
- [东软信息学院](http://mirrors.neusoft.edu.cn/)
+ - [校园网联合镜像站](https://mirrors.cernet.edu.cn)
+
+## 🚪 传送门
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾ 🎯 [钝悟的博客](https://dunwu.github.io/blog/) ◾
diff --git a/assets/docker.xmind b/assets/docker.xmind
new file mode 100644
index 00000000..293f1ff6
Binary files /dev/null and b/assets/docker.xmind differ
diff --git a/docs/git/git.xmind b/assets/linux.xmind
similarity index 62%
rename from docs/git/git.xmind
rename to assets/linux.xmind
index 147612d9..291a618d 100644
Binary files a/docs/git/git.xmind and b/assets/linux.xmind differ
diff --git a/codes/docker/docker-compose-demo/Dockerfile b/codes/docker/docker-compose-demo/Dockerfile
new file mode 100644
index 00000000..7c4b8c7a
--- /dev/null
+++ b/codes/docker/docker-compose-demo/Dockerfile
@@ -0,0 +1,5 @@
+FROM python:3.6-alpine
+ADD . /code
+WORKDIR /code
+RUN pip install redis flask
+CMD ["python", "app.py"]
diff --git a/codes/docker/docker-compose-demo/app.py b/codes/docker/docker-compose-demo/app.py
new file mode 100644
index 00000000..f0dfc208
--- /dev/null
+++ b/codes/docker/docker-compose-demo/app.py
@@ -0,0 +1,13 @@
+from flask import Flask
+from redis import Redis
+
+app = Flask(__name__)
+redis = Redis(host='redis', port=6379)
+
+@app.route('/')
+def hello():
+ count = redis.incr('hits')
+ return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
+
+if __name__ == "__main__":
+ app.run(host="0.0.0.0", debug=True)
diff --git a/codes/docker/docker-compose-demo/docker-compose.yml b/codes/docker/docker-compose-demo/docker-compose.yml
new file mode 100644
index 00000000..80d8ced4
--- /dev/null
+++ b/codes/docker/docker-compose-demo/docker-compose.yml
@@ -0,0 +1,10 @@
+version: '3'
+services:
+
+ web:
+ build: .
+ ports:
+ - "5000:5000"
+
+ redis:
+ image: "redis:alpine"
diff --git a/codes/docker/docker-compose-demo/run.sh b/codes/docker/docker-compose-demo/run.sh
new file mode 100644
index 00000000..0913e24e
--- /dev/null
+++ b/codes/docker/docker-compose-demo/run.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+set -x
+docker-compose up
diff --git "a/codes/expect/\350\277\234\347\250\213\347\231\273\345\275\225.sh" "b/codes/expect/\350\277\234\347\250\213\347\231\273\345\275\225.sh"
new file mode 100644
index 00000000..045a0765
--- /dev/null
+++ "b/codes/expect/\350\277\234\347\250\213\347\231\273\345\275\225.sh"
@@ -0,0 +1,29 @@
+#!/usr/bin/expect -f
+
+# -----------------------------------------------------------------------------------------------------
+# expect 交互式脚本示例 - 自动远程登录,并在其他机器上创建一个文件
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+# 设置变量
+set USER "root"
+set PWD "XXXXXX"
+set HOST "127.0.0.2"
+# 设置超时时间
+set timeout 400
+
+# 远程登录
+spawn ssh -p 22 $USER@$HOST
+expect {
+ "yes/no" { send "yes\r"; exp_continue }
+ "password:" { send "$PWD\r" }
+}
+
+# 在其他机器上创建
+expect "#"
+send "touch /home/demo.txt\r"
+expect "#"
+send "echo hello world >> /home/demo.txt\r"
+expect "#"
+# 退出
+send "exit\r"
diff --git a/codes/linux/README.md b/codes/linux/README.md
index 6e95ca7d..5d0cb039 100644
--- a/codes/linux/README.md
+++ b/codes/linux/README.md
@@ -1,4 +1,4 @@
-# Linux 傻瓜式运维脚本
+# CentOS 常规操作运维脚本集合
> **本项目脚本代码用于在 [CentOS](https://www.centos.org/) 机器上安装常用命令工具或开发软件。**
@@ -6,20 +6,20 @@
(1)下载脚本
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/download.sh | bash
```
(2)执行脚本
-```sh
+```shell
cd /tmp/dunwu-ops
./dunwu-ops.sh
```
(3)清除脚本
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/clear.sh | bash
```
diff --git "a/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/lifecycle.sh" "b/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/lifecycle.sh"
new file mode 100644
index 00000000..f3d627d5
--- /dev/null
+++ "b/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/lifecycle.sh"
@@ -0,0 +1,162 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# 应用终止脚本
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+
+# ------------------------------------------------------------------------------ libs
+
+SCRIPTS_DIR=$(cd `dirname $0`; pwd)
+
+if [[ ! -x ${SCRIPTS_DIR}/utils.sh ]]; then
+ logError "${SCRIPTS_DIR}/utils.sh not exists!"
+ exit 1
+fi
+source ${SCRIPTS_DIR}/utils.sh
+
+
+# ------------------------------------------------------------------------------ functions
+
+stopServer() {
+ if [[ ! $1 ]]; then
+ logError "please input java app name"
+ return ${ENV_FAILED}
+ fi
+
+ local appName=$1
+ local pid=`jps | grep ${appName} | awk '{print $1}'`
+ if [[ -n "${pid}" ]]; then
+ kill -9 ${pid}
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ printInfo "stop ${appName} succeed"
+ return ${ENV_SUCCEED}
+ else
+ logError "stop ${appName} failed"
+ return ${ENV_FAILED}
+ fi
+ else
+ printWarn "${appName} is not running"
+ return ${ENV_SUCCEED}
+ fi
+}
+
+startServer() {
+
+ # >>>> validate params
+ if [[ ! $1 ]] || [[ ! $2 ]] || [[ ! $3 ]] || [[ ! $4 ]]; then
+ logError "you must input following params in order:"
+ echo -e "${ENV_COLOR_B_RED}"
+ echo " (1)jarPath"
+ echo " (2)libPath"
+ echo " (3)confPath"
+ echo " (4)logPath"
+ echo " (5)appName [optional]"
+ echo " (6)port [optional]"
+ echo " (7)profile [optional]"
+ echo " (8)debug [optional]"
+ echo -e "\nEg. startServer /usr/lib/dunwu/app.jar /usr/lib/dunwu/lib /usr/lib/dunwu/conf /var/log/dunwu dunwu 8888 prod off"
+ echo -e "${ENV_COLOR_RESET}"
+ return ${ENV_FAILED}
+ fi
+
+ local jarPath=$1
+ local libPath=$2
+ local confPath=$3
+ local logPath=$4
+ local appName=${5:-myapp}
+ local port=${6:-8888}
+ local profile=${7:-prod}
+ local debug=${8:-off}
+
+ # >>>> 1. check java app is started or not
+ # >>>> 1.1. exit script if the app is started
+ local pid=`jps | grep ${appName} | awk '{print $1}'`
+ if [[ -n "${pid}" ]]; then
+ printInfo "${appName} is started, PID: ${pid}"
+ return ${ENV_SUCCEED}
+ fi
+
+ # >>>> 2. package options
+ # GC OPTS
+ local javaOptions="-server -Xms1g -Xmx2g -Xss256k"
+ javaOptions="${javaOptions} -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:NewRatio=4"
+
+ # GC LOG OPTS
+ javaOptions="${javaOptions} -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps"
+ javaOptions="${javaOptions} -verbose:gc -Xloggc:${logPath}/${appName}.gc.log"
+ javaOptions="${javaOptions} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
+
+ # Heap Dump OPTS
+ javaOptions="${javaOptions} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError"
+ javaOptions="${javaOptions} -XX:HeapDumpPath=${logPath}/${appName}.heapdump.hprof"
+
+ # APP OPTS
+ javaOptions="${javaOptions} -Dsun.net.inetaddr.ttl=60 -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8"
+ if [[ ${profile} ]]; then
+ javaOptions="${javaOptions} -Dspring.profiles.active=${profile}"
+ fi
+
+ # DEBUG OPTS
+ if [[ "${debug}" == "on" ]]; then
+ # JMX OPTS
+ local ip=$(ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d '/')
+ local jmxPort=$(expr 10000 + ${port})
+ javaOptions="${javaOptions} -Dcom.sun.management.jmxremote=true"
+ javaOptions="${javaOptions} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
+ javaOptions="${javaOptions} -Djava.rmi.server.hostname=${ip} -Dcom.sun.management.jmxremote.port=${jmxPort}"
+
+ # Remote Debug
+ local debugPort=$(expr 20000 + ${port})
+ javaOptions="${javaOptions} -Xdebug -Xnoagent -Djava.compiler=NONE"
+ javaOptions="${javaOptions} -Xrunjdwp:transport=dt_socket,address=${debugPort},server=y,suspend=n"
+ fi
+
+ # CLASSPATH
+ local appOptions="-classpath ${libPath}/* -Dlogging.config=file:${confPath}/logback.${profile}.xml"
+ local springConfigFiles="classpath:/,classpath:/config/"
+ local springConfigFiles="${springConfigFiles},file:${confPath}/,file:${confPath}/application.properties"
+ appOptions="${appOptions} --spring.config.location=${springConfigFiles}"
+ appOptions="${appOptions} --spring.cache.ehcache.config=file:${confPath}/config/ehcache.xml"
+ if [[ ${port} ]]; then
+ appOptions="${appOptions} --server.port=${port}"
+ fi
+
+ # >>>> 3. create log dir and console log file
+ local consoleLogPath=${logPath}/${appName}.console.log
+ mkdir -p ${logPath}
+ if [[ ! -x ${consoleLogPath} ]]; then
+ touch ${consoleLogPath}
+ fi
+
+ # >>>> 4. start java app
+ # print bootstrap info
+ printInfo "starting ${appName}"
+ echo -e "${ENV_COLOR_B_GREEN}"
+ echo -e "${ENV_COLOR_B_CYAN}\nBOOT PARAMS:${ENV_COLOR_B_GREEN}\n\n"
+ echo "appName=${appName}"
+ echo "jarPath=${jarPath}"
+ echo "libPath=${libPath}"
+ echo "confPath=${confPath}"
+ echo "logPath=${logPath}"
+ echo "port=${port}"
+ echo "profile=${profile}"
+ echo "debug=${debug}"
+ echo -e "${ENV_COLOR_B_CYAN}\nEXEC CLI:${ENV_COLOR_B_GREEN}\n\n"
+ echo "nohup java ${javaOptions} -jar ${jarPath} ${appOptions} >> ${consoleLogPath} 2>&1 &"
+ echo -e "${ENV_COLOR_RESET}"
+
+ # exec boot cli
+ nohup java ${javaOptions} -jar ${jarPath} ${appOptions} >> ${consoleLogPath} 2>&1 &
+
+ # >>>> 5. check java app is started or not
+ local pid=`jps | grep ${appName} | awk '{print $1}'`
+ if [[ -n "${pid}" ]]; then
+ printInfo "start ${appName} succeed, PID: ${pid}"
+ return ${ENV_SUCCEED}
+ else
+ logError "start ${appName} failed"
+ return ${ENV_FAILED}
+ fi
+}
diff --git "a/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/start.sh" "b/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/start.sh"
new file mode 100644
index 00000000..6aa0382e
--- /dev/null
+++ "b/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/start.sh"
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# myapp 启动脚本,用于【虚拟机环境】
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+
+# ------------------------------------------------------------------------------ libs
+
+SCRIPTS_DIR=$(dirname ${BASH_SOURCE[0]})
+if [[ ! -x ${SCRIPTS_DIR}/lifecycle.sh ]]; then
+ logError "${SCRIPTS_DIR}/lifecycle.sh not exists!"
+ exit 1
+fi
+source ${SCRIPTS_DIR}/lifecycle.sh
+
+
+# ------------------------------------------------------------------------------ main
+
+APP_DIR=$(cd `dirname $0`/..; pwd)
+
+export LANG="zh_CN.UTF-8"
+APP=myapp
+JAR_PATH=${APP_DIR}/myapp.jar
+LIB_PATH=${APP_DIR}/lib
+CONF_PATH=${APP_DIR}/config
+LOG_DIR=/var/log/dunwu
+PORT=8888
+PROFILE=prod
+DEBUG=off
+
+declare -a serial
+serial=(on off)
+echo -n "是否启动 debug 模式(可选值:on|off):"
+read DEBUG
+if ! echo ${serial[@]} | grep -q ${DEBUG}; then
+ echo "是否启动 debug 模式(可选值:on|off)"
+ exit 1
+fi
+
+startServer ${JAR_PATH} ${LIB_PATH} ${CONF_PATH} ${LOG_DIR} ${APP} ${PORT} ${PROFILE} ${DEBUG}
diff --git "a/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/stop.sh" "b/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/stop.sh"
new file mode 100644
index 00000000..a73cc5df
--- /dev/null
+++ "b/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/stop.sh"
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# 应用启动脚本
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+
+# ------------------------------------------------------------------------------ libs
+
+SCRIPTS_DIR=$(dirname ${BASH_SOURCE[0]})
+if [[ ! -x ${SCRIPTS_DIR}/lifecycle.sh ]]; then
+ logError "${SCRIPTS_DIR}/lifecycle.sh not exists!"
+ exit 1
+fi
+source ${SCRIPTS_DIR}/lifecycle.sh
+
+
+# ------------------------------------------------------------------------------ main
+
+export LANG="zh_CN.UTF-8"
+stopServer myapp
diff --git "a/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/utils.sh" "b/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/utils.sh"
new file mode 100644
index 00000000..259ded00
--- /dev/null
+++ "b/codes/linux/build/Java\345\272\224\347\224\250\350\277\220\350\241\214\350\204\232\346\234\254\346\250\241\346\235\277/utils.sh"
@@ -0,0 +1,115 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# Shell Utils
+# 使用此脚本,应该先 export ENV_LOG_PATH,指定日志路径;否则将使用默认日志路径 /var/log/shell.log
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env params
+
+# 颜色状态
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Underline Color
+export ENV_COLOR_U_BLACK="\033[4;30m"
+export ENV_COLOR_U_RED="\033[4;31m"
+export ENV_COLOR_U_GREEN="\033[4;32m"
+export ENV_COLOR_U_YELLOW="\033[4;33m"
+export ENV_COLOR_U_BLUE="\033[4;34m"
+export ENV_COLOR_U_MAGENTA="\033[4;35m"
+export ENV_COLOR_U_CYAN="\033[4;36m"
+export ENV_COLOR_U_WHITE="\033[4;37m"
+# Background Color
+export ENV_COLOR_BG_BLACK="\033[40m"
+export ENV_COLOR_BG_RED="\033[41m"
+export ENV_COLOR_BG_GREEN="\033[42m"
+export ENV_COLOR_BG_YELLOW="\033[43m"
+export ENV_COLOR_BG_BLUE="\033[44m"
+export ENV_COLOR_BG_MAGENTA="\033[45m"
+export ENV_COLOR_BG_CYAN="\033[46m"
+export ENV_COLOR_BG_WHITE="\033[47m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# 常用状态值
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+
+# ------------------------------------------------------------------------------ functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+# 日志路径
+LOG_PATH=${ENV_LOG_PATH:-/var/log/shell.log}
+# 日志目录
+LOG_DIR=${LOG_PATH%/*}
+
+createLogFileIfNotExists() {
+ if [[ ! -x "${LOG_PATH}" ]]; then
+ mkdir -p "${LOG_DIR}"
+ touch "${LOG_PATH}"
+ fi
+}
+
+logInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [INFO] [$0] $@" >> "${LOG_PATH}"
+}
+
+logWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [WARN] [$0] $@" >> "${LOG_PATH}"
+}
+
+logError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [ERROR] [$0] $@" >> "${LOG_PATH}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ logInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ logError "$@ EXECUTE ENV_FAILED"
+ return ${ENV_FAILED}
+ fi
+}
diff --git a/codes/linux/build/helper.sh b/codes/linux/build/helper.sh
index c3e120e1..4b780a02 100644
--- a/codes/linux/build/helper.sh
+++ b/codes/linux/build/helper.sh
@@ -2,7 +2,7 @@
# 打印UI页头信息
function printHeadInfo() {
-cat << EOF
+ cat << EOF
***********************************************************************************
* 欢迎使用项目引导式发布脚本。
* 输入任意键进入脚本操作。
@@ -12,7 +12,7 @@ EOF
# 打印UI页尾信息
function printFootInfo() {
-cat << EOF
+ cat << EOF
***********************************************************************************
@@ -25,18 +25,18 @@ EOF
# 检查文件是否存在,不存在则退出脚本
function checkFileExist() {
- if [ ! -f "$1" ]
- then
- echo "关键文件 $1 找不到,脚本执行结束"
- exit 1
- fi
+ if [ ! -f "$1" ]
+ then
+ echo "关键文件 $1 找不到,脚本执行结束"
+ exit 1
+ fi
}
# 检查文件夹是否存在,不存在则创建
function createFolderIfNotExist() {
- if [ ! -d "$1" ];then
- mkdir -p "$1"
- fi
+ if [ ! -d "$1" ]; then
+ mkdir -p "$1"
+ fi
}
# 记录发布的版本信息
@@ -45,18 +45,18 @@ function createFolderIfNotExist() {
# 第三个参数为代码分支
# 第四个参数为运行环境
function saveVersionInfo() {
- if [ "$1" == "" ] || [ "$2" == "" ] || [ "$3" == "" ] || [ "$4" == "" ]; then
- echo "缺少参数,退出"
- exit 1
- fi
-
- VERSION_LOG_FILE=$1/$2-version.log
- rm -rf ${VERSION_LOG_FILE}
- touch ${VERSION_LOG_FILE}
- chmod 777 ${VERSION_LOG_FILE}
-
- echo -e "\n=================== $2 ===================" >> ${VERSION_LOG_FILE}
- echo "Branch is: $3" >> ${VERSION_LOG_FILE}
- echo "Profile is: $4" >> ${VERSION_LOG_FILE}
- echo "CommitID is : $(git log --pretty=oneline -1)" >> ${VERSION_LOG_FILE}
+ if [ "$1" == "" ] || [ "$2" == "" ] || [ "$3" == "" ] || [ "$4" == "" ]; then
+ echo "缺少参数,退出"
+ exit 1
+ fi
+
+ VERSION_LOG_FILE=$1/$2-version.log
+ rm -rf ${VERSION_LOG_FILE}
+ touch ${VERSION_LOG_FILE}
+ chmod 777 ${VERSION_LOG_FILE}
+
+ echo -e "\n=================== $2 ===================" >> ${VERSION_LOG_FILE}
+ echo "Branch is: $3" >> ${VERSION_LOG_FILE}
+ echo "Profile is: $4" >> ${VERSION_LOG_FILE}
+ echo "CommitID is : $(git log --pretty=oneline -1)" >> ${VERSION_LOG_FILE}
}
diff --git a/codes/linux/build/java-app-boot.sh b/codes/linux/build/java-app-boot.sh
index 4879c08c..cbd8debe 100644
--- a/codes/linux/build/java-app-boot.sh
+++ b/codes/linux/build/java-app-boot.sh
@@ -7,76 +7,76 @@
# 检查脚本参数,如必要参数未传入,退出脚本。
function checkInput() {
- if [ "${app}" == "" ] || [ "${oper}" == "" ] || [ "${javaArgs}" == "" ] || [ "${classpathArgs}" == "" ] || [ "${bootstrapClass}" == "" ]; then
- echo "请输入脚本参数:app oper javaArgs classpathArgs bootstrapClass"
- echo " app: 应用名。"
- echo " oper: 运行环境(必填)。可选值:start|stop|restart"
- echo " javaArgs: JVM 参数(必填)。"
- echo " classpathArgs: classpath参数(必填)。"
- echo " bootstrapClass: 启动类(必填)。"
- exit 0
- fi
+ if [ "${app}" == "" ] || [ "${oper}" == "" ] || [ "${javaArgs}" == "" ] || [ "${classpathArgs}" == "" ] || [ "${bootstrapClass}" == "" ]; then
+ echo "请输入脚本参数:app oper javaArgs classpathArgs bootstrapClass"
+ echo " app: 应用名。"
+ echo " oper: 运行环境(必填)。可选值:start|stop|restart"
+ echo " javaArgs: JVM 参数(必填)。"
+ echo " classpathArgs: classpath参数(必填)。"
+ echo " bootstrapClass: 启动类(必填)。"
+ exit 0
+ fi
}
# 检查文件夹是否存在,不存在则创建
function createFolderIfNotExist() {
- if [ ! -d "$1" ];then
- mkdir -p "$1"
- fi
+ if [ ! -d "$1" ]; then
+ mkdir -p "$1"
+ fi
}
# 检查服务是否已经启动
pids=""
function checkStarted() {
- pids=`ps -ef | grep java | grep ${app} | awk '{print $2}'`
- if [ -n "${pids}" ]; then
- return 0
- else
- return 1
- fi
+ pids=`ps -ef | grep java | grep ${app} | awk '{print $2}'`
+ if [ -n "${pids}" ]; then
+ return 0
+ else
+ return 1
+ fi
}
function main() {
- case "${oper}" in
- start )
- echo -n "starting server: "
- # 检查服务是否已经启动
- if checkStarted ;then
- echo "ERROR: server already started!"
- echo "PID: ${pids}"
- exit 1
- fi
+ case "${oper}" in
+ start)
+ echo -n "starting server: "
+ # 检查服务是否已经启动
+ if checkStarted; then
+ echo "ERROR: server already started!"
+ echo "PID: ${pids}"
+ exit 1
+ fi
- args="${javaArgs} -classpath ${classpathArgs} ${bootstrapClass}"
- echo -e "statup params:\n ${args}"
+ args="${javaArgs} -classpath ${classpathArgs} ${bootstrapClass}"
+ echo -e "statup params:\n ${args}"
- #启动服务
- touch ${LOG_DIR}/${app}-startup.log
- nohup java ${args} > ${LOG_DIR}/${app}-startup.log 2>&1 &
- # echo -e "执行参数:\n${args}"
- echo -e "\nthe server is started..."
- ;;
- stop )
- echo -n "stopping server: "
- #dubbo提供优雅停机, 不能使用kill -9
- if checkStarted ;then
- kill ${pids}
- echo -e "\nthe server is stopped..."
- else
- echo -e "\nno server to be stopped..."
- fi
- ;;
- restart )
- $0 ${app} stop "${javaArgs}" "${classpathArgs}" "${bootstrapClass}"
- sleep 5
- $0 ${app} start "${javaArgs}" "${classpathArgs}" "${bootstrapClass}"
- ;;
- * )
- echo "Invalid oper: ${oper}."
- exit 1
- esac
+ #启动服务
+ touch ${LOG_DIR}/${app}-startup.log
+ nohup java ${args} > ${LOG_DIR}/${app}-startup.log 2>&1 &
+ # echo -e "执行参数:\n${args}"
+ echo -e "\nthe server is started..."
+ ;;
+ stop)
+ echo -n "stopping server: "
+ #dubbo提供优雅停机, 不能使用kill -9
+ if checkStarted; then
+ kill ${pids}
+ echo -e "\nthe server is stopped..."
+ else
+ echo -e "\nno server to be stopped..."
+ fi
+ ;;
+ restart)
+ $0 ${app} stop "${javaArgs}" "${classpathArgs}" "${bootstrapClass}"
+ sleep 5
+ $0 ${app} start "${javaArgs}" "${classpathArgs}" "${bootstrapClass}"
+ ;;
+ *)
+ echo "Invalid oper: ${oper}."
+ exit 1
+ esac
- exit 0
+ exit 0
}
######################################## MAIN ########################################
diff --git a/codes/linux/build/java-app-release.sh b/codes/linux/build/java-app-release.sh
index 45d916c3..7f34ab46 100644
--- a/codes/linux/build/java-app-release.sh
+++ b/codes/linux/build/java-app-release.sh
@@ -7,41 +7,41 @@
# 检查脚本参数,如必要参数未传入,退出脚本。
checkInput() {
- if [ "${branch}" == "" ] || [ "${profile}" == "" ]; then
- echo "请输入脚本参数:branch profile"
- echo " branch: git分支(必填)。如 feature/1.1.16, master"
- echo " profile: 运行环境(必填)。可选值:development | test"
- echo "例:./java-app-release.sh feature/1.1.16 test"
- exit 0
- fi
+ if [ "${branch}" == "" ] || [ "${profile}" == "" ]; then
+ echo "请输入脚本参数:branch profile"
+ echo " branch: git分支(必填)。如 feature/1.1.16, master"
+ echo " profile: 运行环境(必填)。可选值:development | test"
+ echo "例:./java-app-release.sh feature/1.1.16 test"
+ exit 0
+ fi
}
# 检查文件是否存在,不存在则退出脚本
checkFileExist() {
- if [ ! -f "$1" ]
- then
- echo "关键文件 $1 找不到,脚本执行结束"
- exit 0
- fi
+ if [ ! -f "$1" ]
+ then
+ echo "关键文件 $1 找不到,脚本执行结束"
+ exit 0
+ fi
}
# 检查文件夹是否存在,不存在则创建
createFolderIfNotExist() {
- if [ ! -d "$1" ];then
- mkdir -p "$1"
- fi
+ if [ ! -d "$1" ]; then
+ mkdir -p "$1"
+ fi
}
# 记录发布的版本信息
saveVersionInfo() {
- rm -rf ${VERSION_LOG_FILE}
- touch ${VERSION_LOG_FILE}
- chmod 777 ${VERSION_LOG_FILE}
-
- echo -e "\n=================== Version Info ===================" >> ${VERSION_LOG_FILE}
- echo "Branch is: ${branch}" >> ${VERSION_LOG_FILE}
- echo "Profile is: ${profile}" >> ${VERSION_LOG_FILE}
- echo "CommitID is : $(git log --pretty=oneline -1)" >> ${VERSION_LOG_FILE}
+ rm -rf ${VERSION_LOG_FILE}
+ touch ${VERSION_LOG_FILE}
+ chmod 777 ${VERSION_LOG_FILE}
+
+ echo -e "\n=================== Version Info ===================" >> ${VERSION_LOG_FILE}
+ echo "Branch is: ${branch}" >> ${VERSION_LOG_FILE}
+ echo "Profile is: ${profile}" >> ${VERSION_LOG_FILE}
+ echo "CommitID is : $(git log --pretty=oneline -1)" >> ${VERSION_LOG_FILE}
}
######################################## MAIN ########################################
@@ -50,7 +50,8 @@ export LANG="zh_CN.UTF-8"
# 设置全局常量
LOG_DIR=/home/zp/log/
-SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd)
+SCRIPT_DIR=$(cd "$(dirname "$0")";
+pwd)
SOURCE_DIR=/home/zp/source/
APP_NAME=XXX
RESOURCES_DIR=/home/zp/source/${APP_NAME}/src/main/resources
@@ -73,10 +74,10 @@ echo ">>>>>>>>>>>>>> 2. 更新代码"
${UPDATE_CODE_SCRIPT_FILE} ${APP_NAME} ${branch} ${SOURCE_DIR}
execode=$?
if [ "${execode}" == "0" ]; then
- echo "更新代码成功"
+ echo "更新代码成功"
else
- echo "更新代码失败"
- exit 1
+ echo "更新代码失败"
+ exit 1
fi
echo ">>>>>>>>>>>>>> 3. 替换配置"
@@ -87,12 +88,12 @@ cd ${SOURCE_DIR}/ck-lion
mvn clean package -e -Dmaven.test.skip=true | tee ${MAVEN_LOG_FILE}
eexecode=$?
if [ "${execode}" == "0" ]; then
- echo "构建编译成功"
- echo "编译详情见:${MAVEN_LOG_FILE}"
+ echo "构建编译成功"
+ echo "编译详情见:${MAVEN_LOG_FILE}"
else
- echo "构建编译失败"
- echo "编译详情见:${MAVEN_LOG_FILE}"
- exit 1
+ echo "构建编译失败"
+ echo "编译详情见:${MAVEN_LOG_FILE}"
+ exit 1
fi
echo ">>>>>>>>>>>>>> 5. 启动应用"
@@ -101,10 +102,10 @@ echo 3 > /proc/sys/vm/drop_caches
${SCRIPT_DIR}/java-app-run.sh ${profile} start
execode=$?
if [ "${execode}" == "0" ]; then
- echo "启动应用成功"
+ echo "启动应用成功"
else
- echo "启动应用失败"
- exit 1
+ echo "启动应用失败"
+ exit 1
fi
echo ">>>>>>>>>>>>>> 6. 记录发布的版本信息"
diff --git a/codes/linux/build/java-app-run.sh b/codes/linux/build/java-app-run.sh
index 88dfc4e7..69006de1 100644
--- a/codes/linux/build/java-app-run.sh
+++ b/codes/linux/build/java-app-run.sh
@@ -7,51 +7,51 @@
# 检查脚本参数,如必要参数未传入,退出脚本。
function checkInput() {
- if [ "${profile}" == "" ] || [ "${oper}" == "" ]; then
- echo "请输入脚本参数:profile oper [debug]"
- echo " profile: 运行环境(必填)。可选值:development|test"
- echo " oper: 运行环境(必填)。可选值:start|stop|restart"
- echo " debug: debug启动开关。默认不填为不启动。"
- exit 0
- fi
+ if [ "${profile}" == "" ] || [ "${oper}" == "" ]; then
+ echo "请输入脚本参数:profile oper [debug]"
+ echo " profile: 运行环境(必填)。可选值:development|test"
+ echo " oper: 运行环境(必填)。可选值:start|stop|restart"
+ echo " debug: debug启动开关。默认不填为不启动。"
+ exit 0
+ fi
}
#检查文件是否存在,不存在则退出脚本
function checkFileExist() {
- if [ ! -f "$1" ]
- then
- echo "关键文件 $1 找不到,脚本执行结束"
- exit 0
- fi
+ if [ ! -f "$1" ]
+ then
+ echo "关键文件 $1 找不到,脚本执行结束"
+ exit 0
+ fi
}
# 封装启动参数,调用启动脚本
-function main(){
- APP_NAME=ck-lion
+function main() {
+ APP_NAME=ck-lion
- # JVM 参数
- JAVA_OPTS=" -Djava.awt.headless=true -Dfile.encoding=UTF8 -Djava.net.preferIPv4Stack=true -Ddubbo.shutdown.hook=true -Dspring.profiles.active=${profile} -Djava.security.egd=file:/dev/./urandom -Xms1024m -Xmx1024m -Xss2m "
- JAVA_DEBUG_OPTS=""
- if [ "$2" == "debug" ]; then
- JAVA_DEBUG_OPTS=" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=2236,server=y,suspend=n "
- shift
- fi
- javaArgs=" ${JAVA_OPTS} ${JAVA_DEBUG_OPTS} "
+ # JVM 参数
+ JAVA_OPTS=" -Djava.awt.headless=true -Dfile.encoding=UTF8 -Djava.net.preferIPv4Stack=true -Ddubbo.shutdown.hook=true -Dspring.profiles.active=${profile} -Djava.security.egd=file:/dev/./urandom -Xms1024m -Xmx1024m -Xss2m "
+ JAVA_DEBUG_OPTS=""
+ if [ "$2" == "debug" ]; then
+ JAVA_DEBUG_OPTS=" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=2236,server=y,suspend=n "
+ shift
+ fi
+ javaArgs=" ${JAVA_OPTS} ${JAVA_DEBUG_OPTS} "
- # classpath 参数
- classpathArgs="${SERVER_ROOT}/WEB-INF/classes:${SERVER_ROOT}/WEB-INF/lib/*"
+ # classpath 参数
+ classpathArgs="${SERVER_ROOT}/WEB-INF/classes:${SERVER_ROOT}/WEB-INF/lib/*"
- # 启动类
- bootstrapClass="com.alibaba.dubbo.container.Main"
+ # 启动类
+ bootstrapClass="com.alibaba.dubbo.container.Main"
- ${SCRIPT_DIR}/java-app-boot.sh ${APP_NAME} ${oper} "${javaArgs}" "${classpathArgs}" "${bootstrapClass}"
- execode=$?
- if [ "${execode}" == "0" ]; then
- echo "执行操作成功"
- else
- echo "执行操作失败"
- exit 1
- fi
+ ${SCRIPT_DIR}/java-app-boot.sh ${APP_NAME} ${oper} "${javaArgs}" "${classpathArgs}" "${bootstrapClass}"
+ execode=$?
+ if [ "${execode}" == "0" ]; then
+ echo "执行操作成功"
+ else
+ echo "执行操作失败"
+ exit 1
+ fi
}
######################################## MAIN ########################################
@@ -59,7 +59,8 @@ function main(){
export LANG="zh_CN.UTF-8"
# 设置全局常量
-SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd)
+SCRIPT_DIR=$(cd "$(dirname "$0")";
+pwd)
SOURCE_DIR=/home/zp/source/
APP_NAME=XXX
SERVER_ROOT=/home/zp/source/${APP_NAME}/target/
diff --git a/codes/linux/build/js-app-release.sh b/codes/linux/build/js-app-release.sh
index ec5aab49..aa08a21c 100644
--- a/codes/linux/build/js-app-release.sh
+++ b/codes/linux/build/js-app-release.sh
@@ -5,50 +5,50 @@
# 检查脚本参数,如必要参数未传入,退出脚本。
function checkInput() {
- if [ "${branch}" == "" ]; then
- echo "请输入脚本参数:branch"
- echo " branch: git分支。如 feature/1.1.16, master"
- exit 1
- fi
+ if [ "${branch}" == "" ]; then
+ echo "请输入脚本参数:branch"
+ echo " branch: git分支。如 feature/1.1.16, master"
+ exit 1
+ fi
}
# 脚本主方法
function main() {
- echo ">>>>>>>>>>>>>> 1. 更新代码"
- ${SCRIPT_DIR}/update-code.sh ${APP} ${branch} ${SOURCE_DIR}
- execode=$?
- if [ "${execode}" == "0" ]; then
- echo "更新代码成功"
- else
- echo "更新代码失败"
- exit 1
- fi
+ echo ">>>>>>>>>>>>>> 1. 更新代码"
+ ${SCRIPT_DIR}/update-code.sh ${APP} ${branch} ${SOURCE_DIR}
+ execode=$?
+ if [ "${execode}" == "0" ]; then
+ echo "更新代码成功"
+ else
+ echo "更新代码失败"
+ exit 1
+ fi
- echo ">>>>>>>>>>>>>> 2. 替换配置"
- # 有的应用此处可能需要替换配置
+ echo ">>>>>>>>>>>>>> 2. 替换配置"
+ # 有的应用此处可能需要替换配置
- echo ">>>>>>>>>>>>>> 3. 构建编译"
- cd ${SOURCE_DIR}/${APP}
- source "${HOME}/.nvm/nvm.sh"
- nvm use 8.9
- npm install
- if [ "${profile}" == "develop" ] || [ "${profile}" == "test" ]; then
- npm start
- elif [ "${profile}" == "preview" ] || [ "${profile}" == "product" ]; then
- npm run build
- fi
- execode=$?
- if [ "${execode}" == "0" ]; then
- echo "构建编译成功"
- else
- echo "构建编译失败"
- exit 1
- fi
+ echo ">>>>>>>>>>>>>> 3. 构建编译"
+ cd ${SOURCE_DIR}/${APP}
+ source "${HOME}/.nvm/nvm.sh"
+ nvm use 8.9
+ npm install
+ if [ "${profile}" == "develop" ] || [ "${profile}" == "test" ]; then
+ npm start
+ elif [ "${profile}" == "preview" ] || [ "${profile}" == "product" ]; then
+ npm run build
+ fi
+ execode=$?
+ if [ "${execode}" == "0" ]; then
+ echo "构建编译成功"
+ else
+ echo "构建编译失败"
+ exit 1
+ fi
- echo ">>>>>>>>>>>>>> 4. 记录发布的版本信息"
- saveVersionInfo ${LOG_DIR} ${APP} ${branch} ${profile}
+ echo ">>>>>>>>>>>>>> 4. 记录发布的版本信息"
+ saveVersionInfo ${LOG_DIR} ${APP} ${branch} ${profile}
- echo ">>>>>>>>>>>>>> 发布应用结束"
+ echo ">>>>>>>>>>>>>> 发布应用结束"
}
######################################## MAIN ########################################
@@ -59,7 +59,8 @@ export LANG="zh_CN.UTF-8"
APP=blog
LOG_DIR=/home/zp/log
SOURCE_DIR=/home/zp/source
-SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd)
+SCRIPT_DIR=$(cd "$(dirname "$0")";
+pwd)
# 装载函数库
. ${SCRIPT_DIR}/helper.sh
diff --git a/codes/linux/build/main.sh b/codes/linux/build/main.sh
index a74f73a1..7e8f2abe 100644
--- a/codes/linux/build/main.sh
+++ b/codes/linux/build/main.sh
@@ -7,7 +7,7 @@
# 选择应用
function chooseAppName() {
-cat << EOF
+ cat << EOF
请选择应用名(数字或关键字均可)。
可选值如下:
[0] all (所有应用)
@@ -15,28 +15,28 @@ cat << EOF
[2] APP2
EOF
-while read app
-do
- case ${app} in
- 0 )
- app=all
- break ;;
- 1 )
- app=js-app
- break ;;
- 2 )
- app=APP2
- break ;;
- all | js-app | APP2 )
- break ;;
- * ) echo "无法识别 ${app}" ;;
- esac
-done
+ while read app
+ do
+ case ${app} in
+ 0)
+ app=all
+ break ;;
+ 1)
+ app=js-app
+ break ;;
+ 2)
+ app=APP2
+ break ;;
+ all | js-app | APP2)
+ break ;;
+ *) echo "无法识别 ${app}" ;;
+ esac
+ done
}
# 选择操作
function chooseOper() {
-cat << EOF
+ cat << EOF
请选择想要执行的操作(数字或关键字均可)。
可选值如下:
[1] start
@@ -44,44 +44,44 @@ cat << EOF
[3] stop
EOF
-while read oper
-do
- case ${oper} in
- 1 )
- oper=start
- break ;;
- 2 )
- oper=restart
- break ;;
- 3 )
- oper=stop
- break ;;
- start | restart | stop )
- break ;;
- * ) echo "无法识别 ${oper}" ;;
- esac
-done
+ while read oper
+ do
+ case ${oper} in
+ 1)
+ oper=start
+ break ;;
+ 2)
+ oper=restart
+ break ;;
+ 3)
+ oper=stop
+ break ;;
+ start | restart | stop)
+ break ;;
+ *) echo "无法识别 ${oper}" ;;
+ esac
+ done
}
# 选择代码分支
function chooseBranch() {
-cat << EOF
+ cat << EOF
请输入 git 分支。
如:develop、master、feature/xxx
EOF
-read branch
-if [[ "${branch}" =~ ^(feature/)([^ \f\n\r\t\v]+) ]] || [ "${branch}" == "develop" ] || [ "${branch}" == "master" ]; then
- echo "输入了 ${branch}"
-else
- echo "无法识别 ${branch}"
- chooseBranch
-fi
+ read branch
+ if [[ "${branch}" =~ ^ ( feature/ ) ( [^ \f\n\r\t\v]+ ) ]] || [ "${branch}" == "develop" ] || [ "${branch}" == "master" ]; then
+ echo "输入了 ${branch}"
+ else
+ echo "无法识别 ${branch}"
+ chooseBranch
+ fi
}
# 选择运行环境
function chooseProfile() {
-cat << EOF
+ cat << EOF
请选择运行环境(数字或关键字均可)。
可选值:
[1] develop (开发环境)
@@ -90,32 +90,32 @@ cat << EOF
[4] product (生产环境)
EOF
-while read profile
-do
- case ${profile} in
- 1 )
- profile=develop
- break ;;
- 2 )
- profile=test
- break ;;
- 3 )
- profile=preview
- break ;;
- 4 )
- profile=product
- break ;;
- develop | test | preview | product )
- break ;;
- * ) echo "无法识别 ${profile}" ;;
- esac
-done
+ while read profile
+ do
+ case ${profile} in
+ 1)
+ profile=develop
+ break ;;
+ 2)
+ profile=test
+ break ;;
+ 3)
+ profile=preview
+ break ;;
+ 4)
+ profile=product
+ break ;;
+ develop | test | preview | product)
+ break ;;
+ *) echo "无法识别 ${profile}" ;;
+ esac
+ done
}
# 确认选择
function confirmChoice() {
-cat << EOF
+ cat << EOF
===================================================
请确认您的选择:Y/N
app: ${app}
@@ -125,66 +125,66 @@ cat << EOF
===================================================
EOF
- while read confirm
- do
- case ${confirm} in
- y | Y )
- echo -e "\n\n>>>>>>>>>>>>>> 开始发布应用"
- break ;;
- n | N )
- echo -e "重新输入发布参数\n"
- inputParams ;;
- * )
- echo "无法识别 ${confirm}" ;;
- esac
- done
+ while read confirm
+ do
+ case ${confirm} in
+ y | Y)
+ echo -e "\n\n>>>>>>>>>>>>>> 开始发布应用"
+ break ;;
+ n | N)
+ echo -e "重新输入发布参数\n"
+ inputParams ;;
+ *)
+ echo "无法识别 ${confirm}" ;;
+ esac
+ done
}
# 引导式发布应用
function releaseApp() {
- # 输入执行参数
- app=""
- branch=""
- profile=""
- chooseAppName
- chooseOper
- if [ "${oper}" == "stop" ]; then
- confirmChoice
- if [ "${app}" == "all" ]; then
- ${SCRIPT_DIR}/${app}-run.sh stop ${profile}
- else
- ${SCRIPT_DIR}/${app}-run.sh stop ${profile}
- fi
- else
- chooseBranch
- chooseProfile
- confirmChoice
- if [ "${app}" == "all" ]; then
- ${SCRIPT_DIR}/js-app-release.sh ${branch} ${profile}
- else
- ${SCRIPT_DIR}/${app}-release.sh ${branch} ${profile}
- fi
- fi
+ # 输入执行参数
+ app=""
+ branch=""
+ profile=""
+ chooseAppName
+ chooseOper
+ if [ "${oper}" == "stop" ]; then
+ confirmChoice
+ if [ "${app}" == "all" ]; then
+ ${SCRIPT_DIR}/${app}-run.sh stop ${profile}
+ else
+ ${SCRIPT_DIR}/${app}-run.sh stop ${profile}
+ fi
+ else
+ chooseBranch
+ chooseProfile
+ confirmChoice
+ if [ "${app}" == "all" ]; then
+ ${SCRIPT_DIR}/js-app-release.sh ${branch} ${profile}
+ else
+ ${SCRIPT_DIR}/${app}-release.sh ${branch} ${profile}
+ fi
+ fi
}
# 脚本主方法
function main() {
-printHeadInfo
-while read sign
-do
- case ${sign} in
- exit)
- echo "主动退出脚本"
- exit 0 ;;
- * )
- releaseApp ;;
- esac
-
- # 装载函数库
- printFootInfo
-done
+ printHeadInfo
+ while read sign
+ do
+ case ${sign} in
+ exit)
+ echo "主动退出脚本"
+ exit 0 ;;
+ *)
+ releaseApp ;;
+ esac
+
+ # 装载函数库
+ printFootInfo
+ done
}
######################################## MAIN ########################################
@@ -192,7 +192,8 @@ done
export LANG="zh_CN.UTF-8"
# 设置全局常量
-SCRIPT_DIR=$(cd "$(dirname "$0")"; pwd)
+SCRIPT_DIR=$(cd "$(dirname "$0")";
+pwd)
SOURCE_DIR=/home/zp/source/
# 装载函数库
diff --git a/codes/linux/build/spring-boot-run.sh b/codes/linux/build/spring-boot-run.sh
new file mode 100644
index 00000000..2d644c8b
--- /dev/null
+++ b/codes/linux/build/spring-boot-run.sh
@@ -0,0 +1,152 @@
+#!/usr/bin/env bash
+
+##############################################################################
+# console color
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+##############################################################################
+
+JAVA_OPTS=""
+APP_OPTS=""
+packageJavaOpts() {
+
+ # GC OPTS
+ JAVA_OPTS="${JAVA_OPTS} -server -Xms8g -Xmx16g -Xss512k"
+ JAVA_OPTS="${JAVA_OPTS} -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy -XX:MaxGCPauseMillis=150"
+ JAVA_OPTS="${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom"
+
+ # DEBUG OPTS
+ if [[ ${debug} == "on" ]]; then
+
+ # Remote Debug
+ JAVA_OPTS="${JAVA_OPTS} -Xdebug -Xnoagent -Djava.compiler=NONE"
+ JAVA_OPTS="${JAVA_OPTS} -Xrunjdwp:transport=dt_socket,address=28889,server=y,suspend=n"
+
+ # GC LOG
+ JAVA_OPTS="${JAVA_OPTS} -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps"
+ JAVA_OPTS="${JAVA_OPTS} -verbose:gc -Xloggc:${LOG_PATH}/${APP_NAME}.gc.log"
+ JAVA_OPTS="${JAVA_OPTS} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
+
+ # Heap Dump
+ JAVA_OPTS="${JAVA_OPTS} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError"
+ JAVA_OPTS="${JAVA_OPTS} -XX:HeapDumpPath=${LOG_PATH}/${APP_NAME}.heapdump.hprof"
+
+ # JMX OPTS
+ IP=`ip addr | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1`
+ JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote=true"
+ JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
+ JAVA_OPTS="${JAVA_OPTS} -Djava.rmi.server.hostname=${IP} -Dcom.sun.management.jmxremote.port=18889"
+ fi
+
+ # APP OPTS
+ JAVA_OPTS="${JAVA_OPTS} -Dsun.net.inetaddr.ttl=60 -Djava.net.preferIPv4Stack=true"
+ JAVA_OPTS="${JAVA_OPTS} -Dspring.profiles.active=${profile} -Dfile.encoding=UTF-8"
+
+ # CLASSPATH
+ APP_OPTS=" -classpath lib/* -Dlogging.config=file:./config/logback.dev.xml --spring.config.location=classpath:/,classpath:/config/,file:./,file:./config/"
+}
+
+# 检查服务是否已经启动
+pid=""
+checkStarted() {
+ pid=`ps -ef | grep java | grep ${APP_NAME} | awk '{print $2}'`
+ if [[ -n "${pid}" ]]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+main() {
+ case "${oper}" in
+ start)
+ startServer
+ ;;
+ stop)
+ stopServer
+ ;;
+ restart)
+ stopServer
+ sleep 5
+ startServer
+ ;;
+ *)
+ echo "Invalid oper: ${oper}."
+ exit 1
+ esac
+
+ exit 0
+}
+
+stopServer() {
+ echo -n "stopping server: "
+ if checkStarted; then
+ kill -9 ${pid}
+ printf "${GREEN}\n${APP_NAME} is stopped.${RESET}\n"
+ else
+ printf "${RED}\n${APP_NAME} fail to stop.${RESET}\n"
+ fi
+}
+
+startServer() {
+ printf "${BLUE}starting ${APP_NAME}...${RESET}\n"
+ if checkStarted; then
+ printf "${YELLOW}[WARN] ${APP_NAME} already started!${RESET}\n"
+ printf "PID: ${pid}\n"
+ exit 1
+ fi
+
+ packageJavaOpts
+ printf "${CYAN}JVM OPTS:\n ${JAVA_OPTS}${RESET}\n"
+ if [[ ! -f "${LOG_PATH}/start.out" ]]; then
+ touch "${LOG_PATH}/start.out"
+ fi
+ nohup java ${JAVA_OPTS} -jar ${ROOT_DIR}/../spring-boot-app.jar ${APP_OPTS} >> ${LOG_PATH}/start.out 2>&1 &
+ printf "${GREEN}\n${APP_NAME} is started.${RESET}\n"
+}
+
+######################################## MAIN ########################################
+# 设置环境变量
+export LANG="zh_CN.UTF-8"
+ROOT_DIR=$(pwd)
+
+APP_NAME=spring-boot-app
+LOG_PATH=${ROOT_DIR}/../logs
+mkdir -p ${LOG_PATH}
+
+declare -a serial
+serial=( start stop restart )
+echo -n "请选择操作(可选值:start|stop|restart):"
+read oper
+if ! echo "${serial[@]}" | grep -q ${oper}; then
+ echo "请选择正确操作(可选值:start|stop|restart)"
+ exit 1
+fi
+
+if [[ ${oper} == "start" ]] || [[ "${oper}" == "restart" ]]; then
+ declare -a serial2
+ serial2=( prod dev test )
+ echo -n "选择 profile(可选值:prod|dev|test):"
+ read profile
+ if ! echo "${serial2[@]}" | grep -q ${profile}; then
+ echo "请选择正确 profile(可选值:prod|dev|test)"
+ exit 1
+ fi
+
+ declare -a serial3
+ serial3=( on off )
+ echo -n "是否启动 debug 模式(可选值:on|off):"
+ read debug
+ if ! echo "${serial3[@]}" | grep -q ${debug}; then
+ echo "是否启动 debug 模式(可选值:on|off)"
+ exit 1
+ fi
+fi
+
+main
diff --git a/codes/linux/build/update-code.sh b/codes/linux/build/update-code.sh
index 5a3a0df6..c3b14f68 100644
--- a/codes/linux/build/update-code.sh
+++ b/codes/linux/build/update-code.sh
@@ -8,78 +8,78 @@
# 检查脚本参数,如必要参数未传入,退出脚本。
checkInput() {
- if [ "${repository}" == "" ] || [ "${branch}" == "" ]; then
- echo "请输入脚本参数:repository branch [source] [target]"
- echo " repository: git 仓储(必填)。"
- echo " branch: git 分支(必填)。如 master/develop"
- echo " source: 代码存放目录。默认为/home/zp/source。"
- echo " target: 代码存放目录。默认为脚本所在目录。"
- exit 1
- fi
+ if [ "${repository}" == "" ] || [ "${branch}" == "" ]; then
+ echo "请输入脚本参数:repository branch [source] [target]"
+ echo " repository: git 仓储(必填)。"
+ echo " branch: git 分支(必填)。如 master/develop"
+ echo " source: 代码存放目录。默认为/home/zp/source。"
+ echo " target: 代码存放目录。默认为脚本所在目录。"
+ exit 1
+ fi
}
# 检查文件夹是否存在,不存在则创建
function createFolderIfNotExist() {
- if [ ! -d "$1" ];then
- mkdir -p "$1"
- fi
+ if [ ! -d "$1" ]; then
+ mkdir -p "$1"
+ fi
}
# 判断 git 版本库是否存在。根据实际结果修改 ${gitok} 值。
gitok=false
function isGitExist() {
- cd ${SOURCE_DIR}
- if [ -d "${SOURCE_DIR}/${repository}/${target}" ]; then
- cd ${SOURCE_DIR}/${repository}/${target}
- #(1)删除git状态零时文件
- if [ -f "gitstatus.tmp" ]; then
- rm -rf gitstatus.tmp
- fi
-
- #(2) 判断是否存在.git目录
- if [ -d "./.git" ]; then
- #(3) 判断git是否可用
- git status &> gitstatus.tmp
- grep -iwq 'not a git repository' gitstatus.tmp && gitok=false || gitok=true
- fi
-
- #返回到主目录
- cd ${SOURCE_DIR}
- fi
+ cd ${SOURCE_DIR}
+ if [ -d "${SOURCE_DIR}/${repository}/${target}" ]; then
+ cd ${SOURCE_DIR}/${repository}/${target}
+ #(1)删除git状态零时文件
+ if [ -f "gitstatus.tmp" ]; then
+ rm -rf gitstatus.tmp
+ fi
+
+ #(2) 判断是否存在.git目录
+ if [ -d "./.git" ]; then
+ #(3) 判断git是否可用
+ git status &> gitstatus.tmp
+ grep -iwq 'not a git repository' gitstatus.tmp && gitok=false || gitok=true
+ fi
+
+ #返回到主目录
+ cd ${SOURCE_DIR}
+ fi
}
# 如果 git 版本库存在(根据 ${gitok} 值),执行 fetch 操作;反之,执行 clone 操作。
function doFetchOrClone() {
- if ${gitok}; then
- cd ${SOURCE_DIR}/${repository}/${target}
- git reset --hard
- git clean -ffdx
- git fetch
- echo "git fetch ${repository} remote repository 到本地成功"
- else
- #删除所有内容,便于重新进行git clone
- rm -rf ${repository}
- git clone --no-checkout git@github.com:${GITHUB_ACCOUNT}/${repository}.git ${SOURCE_DIR}/${repository}/${target}
- echo "git clone ${repository} remote repository 到本地成功"
- cd ${SOURCE_DIR}/${repository}/${target}
- fi
+ if ${gitok}; then
+ cd ${SOURCE_DIR}/${repository}/${target}
+ git reset --hard
+ git clean -ffdx
+ git fetch
+ echo "git fetch ${repository} remote repository 到本地成功"
+ else
+ #删除所有内容,便于重新进行git clone
+ rm -rf ${repository}
+ git clone --no-checkout git@github.com:${GITHUB_ACCOUNT}/${repository}.git ${SOURCE_DIR}/${repository}/${target}
+ echo "git clone ${repository} remote repository 到本地成功"
+ cd ${SOURCE_DIR}/${repository}/${target}
+ fi
}
# 切换到 ${branch} 分支
function doCheckout() {
- echo "检出 ${repository} ${branch} 分支代码"
- isRemoteBranch=false
- gitRemoteBranch=`git branch -r`
- echo -e "$gitRemoteBranch" | grep -iwq ${branch} && isRemoteBranch=true || isRemoteBranch=false
- if ${isRemoteBranch}; then
- echo "找到 ${branch} 分支。"
- git checkout -f 'origin/'${branch}
- else
- echo "未找到 ${branch} 分支!"
- exit 2
- fi
- echo "更新子模块代码"
- git submodule update --init --recursive --force
+ echo "检出 ${repository} ${branch} 分支代码"
+ isRemoteBranch=false
+ gitRemoteBranch=`git branch -r`
+ echo -e "$gitRemoteBranch" | grep -iwq ${branch} && isRemoteBranch=true || isRemoteBranch=false
+ if ${isRemoteBranch}; then
+ echo "找到 ${branch} 分支。"
+ git checkout -f 'origin/'${branch}
+ else
+ echo "未找到 ${branch} 分支!"
+ exit 2
+ fi
+ echo "更新子模块代码"
+ git submodule update --init --recursive --force
}
######################################## MAIN ########################################
@@ -96,7 +96,7 @@ checkInput
GITHUB_ACCOUNT=dunwu
SOURCE_DIR=/home/xyz/source
if [ "${source}" != "" ]; then
- SOURCE_DIR=${source}
+ SOURCE_DIR=${source}
fi
createFolderIfNotExist ${SOURCE_DIR}
diff --git a/codes/linux/conf/etc/sysctl.conf b/codes/linux/conf/etc/sysctl.conf
new file mode 100644
index 00000000..727d7317
--- /dev/null
+++ b/codes/linux/conf/etc/sysctl.conf
@@ -0,0 +1,63 @@
+###################################################################################
+# /etc/sysctl.conf 文件用于配置 Linux 内核及网络
+# @author: Zhang Peng
+###################################################################################
+# 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
+net.ipv4.tcp_tw_reuse = 1
+# 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
+net.ipv4.tcp_tw_recycle = 1
+# 如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。
+net.ipv4.tcp_fin_timeout = 2
+# 避免放大攻击
+net.ipv4.icmp_echo_ignore_broadcasts = 1
+# 开启恶意icmp错误消息保护
+net.ipv4.icmp_ignore_bogus_error_responses = 1
+# 开启SYN洪水攻击保护
+net.ipv4.tcp_syncookies = 1
+# 开启并记录欺骗,源路由和重定向包
+net.ipv4.conf.all.log_martians = 1
+net.ipv4.conf.default.log_martians = 1
+# 处理无源路由的包
+net.ipv4.conf.all.accept_source_route = 0
+net.ipv4.conf.default.accept_source_route = 0
+# 开启反向路径过滤
+net.ipv4.conf.all.rp_filter = 1
+net.ipv4.conf.default.rp_filter = 1
+# 确保无人能修改路由表
+net.ipv4.conf.all.accept_redirects = 0
+net.ipv4.conf.default.accept_redirects = 0
+net.ipv4.conf.all.secure_redirects = 0
+net.ipv4.conf.default.secure_redirects = 0
+# 不充当路由器
+net.ipv4.ip_forward = 0
+net.ipv4.conf.all.send_redirects = 0
+net.ipv4.conf.default.send_redirects = 0
+# 开启execshild
+kernel.exec-shield = 1
+kernel.randomize_va_space = 1
+# IPv6设置
+net.ipv6.conf.default.router_solicitations = 0
+net.ipv6.conf.default.accept_ra_rtr_pref = 0
+net.ipv6.conf.default.accept_ra_pinfo = 0
+net.ipv6.conf.default.accept_ra_defrtr = 0
+net.ipv6.conf.default.autoconf = 0
+net.ipv6.conf.default.dad_transmits = 0
+net.ipv6.conf.default.max_addresses = 1
+# 优化LB使用的端口
+# 增加系统文件描述符限制
+fs.file-max = 65535
+# 允许更多的PIDs (减少滚动翻转问题); may break some programs 32768
+kernel.pid_max = 65536
+# 增加系统IP端口限制
+net.ipv4.ip_local_port_range = 2000 65535
+# 增加TCP最大缓冲区大小
+net.ipv4.tcp_rmem = 4096 87380 8388608
+net.ipv4.tcp_wmem = 4096 87380 8388608
+# 增加Linux自动调整TCP缓冲区限制
+# 最小,默认和最大可使用的字节数
+# 最大值不低于4MB,如果你使用非常高的BDP路径可以设置得更高
+# Tcp窗口等
+net.core.rmem_max = 8388608
+net.core.wmem_max = 8388608
+net.core.netdev_max_backlog = 5000
+net.ipv4.tcp_window_scaling = 1
diff --git a/codes/linux/download.sh b/codes/linux/download.sh
index ee6d323c..0438d157 100644
--- a/codes/linux/download.sh
+++ b/codes/linux/download.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-###################################################################################
+# ---------------------------------------------------------------------------------
# 控制台颜色
BLACK="\033[1;30m"
RED="\033[1;31m"
@@ -10,11 +10,10 @@ BLUE="\033[1;34m"
PURPLE="\033[1;35m"
CYAN="\033[1;36m"
RESET="$(tput sgr0)"
-###################################################################################
+# ---------------------------------------------------------------------------------
-printf "${BLUE}"
+printf "${BLUE}\n"
cat << EOF
-
###################################################################################
# linux-tutorial 运维脚本工具集下载脚本
# 下载 https://github.com/dunwu/linux-tutorial 中的所有脚本到当前服务器的
@@ -23,21 +22,27 @@ cat << EOF
# @author: Zhang Peng
# See: https://github.com/dunwu/linux-tutorial
###################################################################################
-
EOF
-printf "${RESET}"
+printf "${RESET}\n"
+
+root=/home/scripts/linux-tutorial
+printf "\n${GREEN}>>>>>>>> Download linux-tutorial to ${root} begin.${RESET}\n"
+command -v yum > /dev/null 2>&1 || {
+ printf "\n${RED}Not detected yum.${RESET}";
+ exit 1;
+}
-path=/home/scripts/linux-tutorial
-printf "\n${GREEN}>>>>>>>> Download linux-tutorial to ${path} begin.${RESET}\n"
-command -v yum >/dev/null 2>&1 || { printf "${RED}Not detected yum.${RESET}"; exit 1; }
-command -v git >/dev/null 2>&1 || { printf "${YELLOW}Not detected git. Install git.${RESET}\n"; yum -y install git; }
+command -v git > /dev/null 2>&1 || {
+ printf "\n${YELLOW}Not detected git. Install git.${RESET}\n";
+ yum install -y git;
+}
-if [[ -d ${path} ]]; then
- cd ${path}
- git pull
+if [[ -d ${root} ]]; then
+ cd ${root}
+ git pull
else
- mkdir -p ${path}
- git clone https://gitee.com/turnon/linux-tutorial.git ${path}
+ mkdir -p ${root}
+ git clone https://gitee.com/turnon/linux-tutorial.git ${root}
fi
-chmod +x -R ${path}
-printf "\n${GREEN}<<<<<<<< Download linux-tutorial to ${path} end.${RESET}\n"
+chmod +x -R ${root}
+printf "\n${GREEN}<<<<<<<< Download linux-tutorial to ${root} end.${RESET}\n"
diff --git a/codes/linux/dunwu-ops.sh b/codes/linux/dunwu-ops.sh
index 161554ef..64a3c53f 100644
--- a/codes/linux/dunwu-ops.sh
+++ b/codes/linux/dunwu-ops.sh
@@ -1,90 +1,204 @@
#!/usr/bin/env bash
-###################################################################################
-# 控制台颜色
-BLACK="\033[1;30m"
-RED="\033[1;31m"
-GREEN="\033[1;32m"
-YELLOW="\033[1;33m"
-BLUE="\033[1;34m"
-PURPLE="\033[1;35m"
-CYAN="\033[1;36m"
-RESET="$(tput sgr0)"
-###################################################################################
+# ------------------------------------------------------------------------------
+# CentOS 常用软件一键安装脚本
+# @author Zhang Peng
+# ------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env
+
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Underline Color
+export ENV_COLOR_U_BLACK="\033[4;30m"
+export ENV_COLOR_U_RED="\033[4;31m"
+export ENV_COLOR_U_GREEN="\033[4;32m"
+export ENV_COLOR_U_YELLOW="\033[4;33m"
+export ENV_COLOR_U_BLUE="\033[4;34m"
+export ENV_COLOR_U_MAGENTA="\033[4;35m"
+export ENV_COLOR_U_CYAN="\033[4;36m"
+export ENV_COLOR_U_WHITE="\033[4;37m"
+# Background Color
+export ENV_COLOR_BG_BLACK="\033[40m"
+export ENV_COLOR_BG_RED="\033[41m"
+export ENV_COLOR_BG_GREEN="\033[42m"
+export ENV_COLOR_BG_YELLOW="\033[43m"
+export ENV_COLOR_BG_BLUE="\033[44m"
+export ENV_COLOR_BG_MAGENTA="\033[45m"
+export ENV_COLOR_BG_CYAN="\033[46m"
+export ENV_COLOR_BG_WHITE="\033[47m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+
+# ------------------------------------------------------------------------------ functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+# 日志路径
+LOG_PATH=${ENV_LOG_PATH:-/var/log/shell.log}
+# 日志目录
+LOG_DIR=${LOG_PATH%/*}
+
+createLogFileIfNotExists() {
+ if [[ ! -x "${LOG_PATH}" ]]; then
+ mkdir -p "${LOG_DIR}"
+ touch "${LOG_PATH}"
+ fi
+}
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
+
+logInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [INFO] [$0] $@" >> "${LOG_PATH}"
+}
+logWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [WARN] [$0] $@" >> "${LOG_PATH}"
+}
+logError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [ERROR] [$0] $@" >> "${LOG_PATH}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ logInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ logError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
+
+# ------------------------------------------------------------------------------ functions
# 打印头部信息
printHeadInfo() {
-printf "${BLUE}"
+printf "${C_B_BLUE}\n"
cat << EOF
-
-***********************************************************************************
-* 欢迎使用 Linux CentOS 环境运维脚本
-* @author: Zhang Peng
-***********************************************************************************
-
+###################################################################################
+# 欢迎使用 Dunwu Shell 运维脚本
+# 适用于 Linux CentOS 环境
+# @author: Zhang Peng
+###################################################################################
EOF
-printf "${RESET}"
+printf "${C_RESET}\n"
}
# 打印尾部信息
printFootInfo() {
-printf "${BLUE}"
+printf "${C_B_BLUE}\n"
cat << EOF
-
-***********************************************************************************
-* 脚本执行结束,感谢使用!
-***********************************************************************************
-
+###################################################################################
+# 脚本执行结束,感谢使用!
+###################################################################################
EOF
-printf "${RESET}"
+printf "${C_RESET}\n"
}
# 检查操作系统环境
-checkOsVersion(){
- if(($1 == 1)); then
- echo -e "检查操作系统环境是否兼容本套脚本"
-
- platform=`uname -i`
- if [[ ${platform} != "x86_64" ]]; then
- echo "脚本仅支持 64 位操作系统!"
- exit 1
- fi
+checkOsVersion() {
+ if (($1 == 1)); then
+ platform=`uname -i`
+ if [[ ${platform} != "x86_64" ]]; then
+ logError "脚本仅支持 64 位操作系统!"
+ exit 1
+ fi
- version=`cat /etc/redhat-release | awk '{print substr($4,1,1)}'`
- if [[ ${version} != 7 ]]; then
- echo "脚本仅支持 CentOS 7!"
- exit 1
- fi
+ version=`cat /etc/redhat-release | awk '{print substr($4,1,1)}'`
+ if [[ ${version} != 7 ]]; then
+ logError "脚本仅支持 CentOS 7!"
+ exit 1
+ fi
+ fi
+}
+
+menus=( "配置系统" "安装软件" "退出" )
+selectAndExecTask() {
+ printHeadInfo
+ PS3="请输入命令编号:"
+ select item in "${menus[@]}"
+ do
+ case ${item} in
+ "配置系统")
+ ./dunwu-sys.sh
+ selectAndExecTask ;;
+ "安装软件")
+ ./dunwu-soft.sh
+ selectAndExecTask ;;
+ "退出")
+ printFootInfo
+ exit 0 ;;
+ *)
+ logWarn "输入项不支持!"
+ selectAndExecTask ;;
+ esac
+ break
+ done
+}
+
+
+# ------------------------------------------------------------------------------ main
- echo -e "脚本可以在本环境运行!"
- fi
-}
-
-menus=("配置系统" "安装软件" "退出")
-main() {
-PS3="请输入命令编号:"
-select item in ${menus[@]}
-do
-case ${item} in
- "配置系统")
- ./dunwu-sys.sh
- main ;;
- "安装软件")
- ./dunwu-soft.sh
- main ;;
- "退出")
- exit 0 ;;
- *)
- printf "输入项不支持!\n"
- main ;;
-esac
-break
-done
-}
-
-######################################## MAIN ########################################
-path=$(cd "$(dirname "$0")"; pwd)
-printHeadInfo
-checkOsVersion 0
-main
-printFootInfo
+checkOsVersion 1
+selectAndExecTask
diff --git a/codes/linux/dunwu-soft.sh b/codes/linux/dunwu-soft.sh
index fdb933fc..c542198c 100644
--- a/codes/linux/dunwu-soft.sh
+++ b/codes/linux/dunwu-soft.sh
@@ -1,60 +1,191 @@
#!/usr/bin/env bash
-###################################################################################
-# 控制台颜色
-BLACK="\033[1;30m"
-RED="\033[1;31m"
-GREEN="\033[1;32m"
-YELLOW="\033[1;33m"
-BLUE="\033[1;34m"
-PURPLE="\033[1;35m"
-CYAN="\033[1;36m"
-RESET="$(tput sgr0)"
-###################################################################################
+# ------------------------------------------------------------------------------
+# CentOS 常用软件一键安装脚本
+# @author Zhang Peng
+# ------------------------------------------------------------------------------
-printf "${BLUE}\n"
-cat << EOF
+# ------------------------------------------------------------------------------ env
+
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Underline Color
+export ENV_COLOR_U_BLACK="\033[4;30m"
+export ENV_COLOR_U_RED="\033[4;31m"
+export ENV_COLOR_U_GREEN="\033[4;32m"
+export ENV_COLOR_U_YELLOW="\033[4;33m"
+export ENV_COLOR_U_BLUE="\033[4;34m"
+export ENV_COLOR_U_MAGENTA="\033[4;35m"
+export ENV_COLOR_U_CYAN="\033[4;36m"
+export ENV_COLOR_U_WHITE="\033[4;37m"
+# Background Color
+export ENV_COLOR_BG_BLACK="\033[40m"
+export ENV_COLOR_BG_RED="\033[41m"
+export ENV_COLOR_BG_GREEN="\033[42m"
+export ENV_COLOR_BG_YELLOW="\033[43m"
+export ENV_COLOR_BG_BLUE="\033[44m"
+export ENV_COLOR_BG_MAGENTA="\033[45m"
+export ENV_COLOR_BG_CYAN="\033[46m"
+export ENV_COLOR_BG_WHITE="\033[47m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+
+# ------------------------------------------------------------------------------ functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+# 日志路径
+LOG_PATH=${ENV_LOG_PATH:-/var/log/shell.log}
+# 日志目录
+LOG_DIR=${LOG_PATH%/*}
+
+createLogFileIfNotExists() {
+ if [[ ! -x "${LOG_PATH}" ]]; then
+ mkdir -p "${LOG_DIR}"
+ touch "${LOG_PATH}"
+ fi
+}
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
-***********************************************************************************
-* 欢迎使用 Linux CentOS 软件安装配置脚本
-* @author: Zhang Peng
-***********************************************************************************
+logInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [INFO] [$0] $@" >> "${LOG_PATH}"
+}
+logWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [WARN] [$0] $@" >> "${LOG_PATH}"
+}
+logError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [ERROR] [$0] $@" >> "${LOG_PATH}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ logInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ logError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
+# ------------------------------------------------------------------------------ functions
+# 打印头部信息
+printHeadInfo() {
+printf "${C_B_BLUE}\n"
+cat << EOF
+###################################################################################
+# 欢迎使用 CentOS 常用软件一键安装脚本
+# 适用于 Linux CentOS 环境
+# @author: Zhang Peng
+###################################################################################
EOF
+printf "${C_RESET}\n"
+}
# print menu
-printf "${PURPLE}"
-menus=(docker fastdfs gitlab jdk8 jenkins kafka maven mongodb mysql nacos nexus nginx nodejs redis rocketmq tomcat8
-zookeeper zsh exit)
-for i in "${!menus[@]}"; do
- index=`expr ${i} + 1`
- val=`expr ${index} % 2`
- printf "[%02d] %-20s" "${index}" "${menus[$i]}"
- if [[ ${val} -eq 0 ]]; then
- printf "\n"
- fi
-done
-printf "\n${RESET}请输入需要安装的软件编号:\n"
+printMenu() {
+ printf "${C_B_MAGENTA}"
+ menus=( docker fastdfs gitlab jdk8 jenkins kafka maven mongodb mysql nacos nexus nginx nodejs redis rocketmq tomcat8 zookeeper zsh exit )
+ for i in "${!menus[@]}"; do
+ index=`expr ${i} + 1`
+ val=`expr ${index} % 2`
+ printf "[%02d] %-20s" "${index}" "${menus[$i]}"
+ if [[ ${val} -eq 0 ]]; then
+ printf "\n"
+ fi
+ done
+
+ printf "\n\n${C_B_BLUE}请选择需要安装的软件:${C_RESET}"
+}
# exec shell to install soft
-doInstall() {
-read -t 30 index
-if [[ -n ${index} ]]; then
- no=`expr ${index} - 1`
- len=${#menus[*]}
- if [[ ${index} -gt ${len} ]]; then
- echo "输入项不支持!"
- exit -1
- fi
- key=${menus[$no]}
- if [[ key == 'exit' ]]; then
- exit 0
- fi
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/${key}-install.sh | bash
- doInstall
-else
- echo "输入项不支持!"
- exit -1
-fi
-}
-doInstall
+main() {
+ printMenu
+ read -t 30 index
+ if [[ -n ${index} ]]; then
+ no=`expr ${index} - 1`
+ len=${#menus[*]}
+ if [[ ${index} -gt ${len} ]]; then
+ logWarn "输入项不支持!"
+ exit 1
+ fi
+ key=${menus[$no]}
+ if [[ ${key} == 'exit' ]]; then
+ logInfo "退出软件安装脚本。"
+ exit 0
+ fi
+ sh soft/${key}-install.sh
+ printf "\n"
+ main
+ else
+ logWarn "输入项不支持!"
+ exit 1
+ fi
+}
+
+# ------------------------------------------------------------------------------ main
+
+printHeadInfo
+main
diff --git a/codes/linux/dunwu-sys.sh b/codes/linux/dunwu-sys.sh
index f1d8747f..9299cee8 100644
--- a/codes/linux/dunwu-sys.sh
+++ b/codes/linux/dunwu-sys.sh
@@ -1,47 +1,186 @@
#!/usr/bin/env bash
-cat << EOF
+# ------------------------------------------------------------------------------
+# CentOS 环境初始化脚本
+# @author Zhang Peng
+# ------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env
+
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Underline Color
+export ENV_COLOR_U_BLACK="\033[4;30m"
+export ENV_COLOR_U_RED="\033[4;31m"
+export ENV_COLOR_U_GREEN="\033[4;32m"
+export ENV_COLOR_U_YELLOW="\033[4;33m"
+export ENV_COLOR_U_BLUE="\033[4;34m"
+export ENV_COLOR_U_MAGENTA="\033[4;35m"
+export ENV_COLOR_U_CYAN="\033[4;36m"
+export ENV_COLOR_U_WHITE="\033[4;37m"
+# Background Color
+export ENV_COLOR_BG_BLACK="\033[40m"
+export ENV_COLOR_BG_RED="\033[41m"
+export ENV_COLOR_BG_GREEN="\033[42m"
+export ENV_COLOR_BG_YELLOW="\033[43m"
+export ENV_COLOR_BG_BLUE="\033[44m"
+export ENV_COLOR_BG_MAGENTA="\033[45m"
+export ENV_COLOR_BG_CYAN="\033[46m"
+export ENV_COLOR_BG_WHITE="\033[47m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+
+# ------------------------------------------------------------------------------ functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+# 日志路径
+LOG_PATH=${ENV_LOG_PATH:-/var/log/shell.log}
+# 日志目录
+LOG_DIR=${LOG_PATH%/*}
+
+createLogFileIfNotExists() {
+ if [[ ! -x "${LOG_PATH}" ]]; then
+ mkdir -p "${LOG_DIR}"
+ touch "${LOG_PATH}"
+ fi
+}
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
+logInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [INFO] [$0] $@" >> "${LOG_PATH}"
+}
+logWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [WARN] [$0] $@" >> "${LOG_PATH}"
+}
+logError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [ERROR] [$0] $@" >> "${LOG_PATH}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ logInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ logError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
+
+# ------------------------------------------------------------------------------ functions
+
+# 打印头部信息
+printHeadInfo() {
+printf "${C_B_BLUE}\n"
+cat << EOF
###################################################################################
-# Linux CentOS 环境初始化脚本(设置环境配置、安装基本的命令工具)
+# 欢迎使用 Dunwu Shell 环境初始化脚本(设置环境配置、安装基本的命令工具)
+# 适用于 Linux CentOS 环境
# @author: Zhang Peng
###################################################################################
-
EOF
+printf "${C_RESET}\n"
+}
-menus=("替换yum镜像" "安装基本的命令工具" "安装常用libs" "系统配置" "全部执行" "退出")
+LINUX_SCRIPTS_DIR=$(cd `dirname $0`; pwd)
+menus=( "替换yum镜像" "安装基本的命令工具" "安装常用libs" "系统配置" "全部执行" "退出" )
main() {
-PS3="请输入命令编号:"
-select item in ${menus[@]}
-do
-case ${item} in
- "替换yum镜像")
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/change-yum-repo.sh | bash
- main ;;
- "安装基本的命令工具")
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/install-tools.sh | bash
- main ;;
- "安装常用libs")
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/install-libs.sh | bash
- main ;;
- "系统配置")
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/sys-settings.sh | bash
- main ;;
- "全部执行")
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/change-yum-repo.sh | bash
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/install-tools | bash
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/install-libs.sh | bash
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/sys-settings.sh | bash
- printf "执行完毕,退出。\n" ;;
- "退出")
- exit 0 ;;
- *)
- printf "输入项不支持!\n"
- main ;;
-esac
-break
-done
-}
-
-######################################## MAIN ########################################
+ PS3="请输入命令编号:"
+ select item in "${menus[@]}"
+ do
+ case ${item} in
+ "替换yum镜像")
+ sh ${LINUX_SCRIPTS_DIR}/sys/change-yum-repo.sh
+ main ;;
+ "安装基本的命令工具")
+ sh ${LINUX_SCRIPTS_DIR}/sys/install-tools.sh
+ main ;;
+ "安装常用libs")
+ sh ${LINUX_SCRIPTS_DIR}/sys/install-libs.sh
+ main ;;
+ "系统配置")
+ sh ${LINUX_SCRIPTS_DIR}/sys/sys-settings.sh ${LINUX_SCRIPTS_DIR}/sys
+ main ;;
+ "全部执行")
+ sh ${LINUX_SCRIPTS_DIR}/sys/change-yum-repo.sh
+ sh ${LINUX_SCRIPTS_DIR}/sys/install-tools.sh
+ sh ${LINUX_SCRIPTS_DIR}/sys/install-libs.sh
+ sh ${LINUX_SCRIPTS_DIR}/sys/sys-settings.sh ${LINUX_SCRIPTS_DIR}/sys
+ logInfo "执行完毕,退出" ;;
+ "退出")
+ exit 0 ;;
+ *)
+ logWarn "输入项不支持!"
+ main ;;
+ esac
+ break
+ done
+}
+
+# ------------------------------------------------------------------------------ main
+
+printHeadInfo
main
diff --git a/codes/linux/libtest/README.md b/codes/linux/libtest/README.md
new file mode 100644
index 00000000..2051e94d
--- /dev/null
+++ b/codes/linux/libtest/README.md
@@ -0,0 +1,11 @@
+# Git 脚本工具
+
+这里汇总一些常用的、简单的 git shell 脚本。
+
+更多功能强大的工具,可以参考 [资源](#资源)
+
+## 资源
+
+- [git-extras](https://github.com/tj/git-extras) - 丰富的 git 扩展支持
+- [gitflow](https://github.com/nvie/gitflow) - git-flow shell 版本
+- [gitflow-avh](https://github.com/petervanderdoes/gitflow-avh) - git-flow shell 版本
\ No newline at end of file
diff --git a/codes/linux/libtest/env-test.sh b/codes/linux/libtest/env-test.sh
new file mode 100644
index 00000000..9d3ad706
--- /dev/null
+++ b/codes/linux/libtest/env-test.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+# 装载其它库
+source ../lib/utils.sh
+
+# ------------------------------------------------------------------------------ 颜色变量测试
+printf "${C_B_YELLOW}测试彩色打印:${C_RESET}\n"
+
+printf "${C_BLACK}Hello.${C_RESET}\n"
+printf "${C_RED}Hello.${C_RESET}\n"
+printf "${C_GREEN}Hello.${C_RESET}\n"
+printf "${C_YELLOW}Hello.${C_RESET}\n"
+printf "${C_BLUE}Hello.${C_RESET}\n"
+printf "${C_MAGENTA}Hello.${C_RESET}\n"
+printf "${C_CYAN}Hello.${C_RESET}\n"
+
+printf "${C_B_BLACK}Hello.${C_RESET}\n"
+printf "${C_B_RED}Hello.${C_RESET}\n"
+printf "${C_B_GREEN}Hello.${C_RESET}\n"
+printf "${C_B_YELLOW}Hello.${C_RESET}\n"
+printf "${C_B_BLUE}Hello.${C_RESET}\n"
+printf "${C_B_MAGENTA}Hello.${C_RESET}\n"
+printf "${C_B_CYAN}Hello.${C_RESET}\n"
+
+printf "${C_U_BLACK}Hello.${C_RESET}\n"
+printf "${C_U_RED}Hello.${C_RESET}\n"
+printf "${C_U_GREEN}Hello.${C_RESET}\n"
+printf "${C_U_YELLOW}Hello.${C_RESET}\n"
+printf "${C_U_BLUE}Hello.${C_RESET}\n"
+printf "${C_U_MAGENTA}Hello.${C_RESET}\n"
+printf "${C_U_CYAN}Hello.${C_RESET}\n"
+
+printf "${C_BG_BLACK}Hello.${C_RESET}\n"
+printf "${C_BG_RED}Hello.${C_RESET}\n"
+printf "${C_BG_GREEN}Hello.${C_RESET}\n"
+printf "${C_BG_YELLOW}Hello.${C_RESET}\n"
+printf "${C_BG_BLUE}Hello.${C_RESET}\n"
+printf "${C_BG_MAGENTA}Hello.${C_RESET}\n"
+printf "${C_BG_CYAN}Hello.${C_RESET}\n"
+
diff --git a/codes/linux/libtest/git-check.sh b/codes/linux/libtest/git-check.sh
new file mode 100644
index 00000000..1761300a
--- /dev/null
+++ b/codes/linux/libtest/git-check.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+source ../lib/utils.sh
+source ../lib/git.sh
+
+##################################### MAIN #####################################
+if [[ $1 ]]; then
+ DIR=$1
+else
+ DIR=$(pwd)
+fi
+
+printInfo "Current path is: ${DIR}."
+
+# 判断是否为 git 项目
+checkGit ${DIR}
+if [[ "${YES}" == "$?" ]]; then
+ printInfo "${DIR} is git project."
+else
+ printError "${DIR} is not git project."
+fi
+
+# 获取 git 分支
+getGitLocalBranch
+printInfo "git local branch: ${GIT_LOCAL_BRANCH}"
+getGitOriginBranch
+printInfo "git origin branch: ${GIT_ORIGIN_BRANCH}"
diff --git a/codes/linux/libtest/git-update.sh b/codes/linux/libtest/git-update.sh
new file mode 100644
index 00000000..eef7edae
--- /dev/null
+++ b/codes/linux/libtest/git-update.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+source ../lib/utils.sh
+source ../lib/git.sh
+
+doCloneOrPullGit() {
+ cloneOrPullGit $1 $2 $3 $4 $5
+ if [[ "$?" == "${SUCCEED}" ]]; then
+ printf "\n${C_GREEN}>>>> Update git project [$2/$3] succeed.${C_RESET}\n"
+ return ${SUCCEED}
+ else
+ printf "\n${C_RED}>>>> Update git project [$2/$3] failed.${C_RESET}\n"
+ return ${FAILED}
+ fi
+}
+
+##################################### MAIN #####################################
+ROOT=$(dirname ${BASH_SOURCE[0]})
+
+# 这里需要根据实际情况替换 Git 仓库、项目组、项目、代码分支
+REPOSITORY="git@gitee.com"
+
+printf "${C_CYAN}Current path is ${ROOT}.${C_RESET}\n"
+
+doCloneOrPullGit ${REPOSITORY} turnon linux-tutorial master ${ROOT}
+r1=$?
+doCloneOrPullGit ${REPOSITORY} turnon nginx-tutorial master ${ROOT}
+r2=$?
+
+if [[ "${r1}" == "${SUCCEED}" && "${r2}" == "${SUCCEED}" ]]; then
+ printf "\n${C_B_GREEN}<<<< Init workspace Succeed.${C_RESET}\n\n"
+ exit ${SUCCEED}
+else
+ printf "\n${C_B_RED}<<<< Init workspace Failed.${C_RESET}\n\n"
+ exit ${FAILED}
+fi
diff --git a/codes/linux/libtest/nodejs-test.sh b/codes/linux/libtest/nodejs-test.sh
new file mode 100644
index 00000000..696371ff
--- /dev/null
+++ b/codes/linux/libtest/nodejs-test.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+# 装载其它库
+source ../lib/nodejs.sh
+
+# ------------------------------------------------------------------------------
+ROOT=$(pwd)
+
+path=${ROOT}
+if [[ $1 ]]; then
+ path=$1
+fi
+
+version=10.15.0
+if [[ $2 ]]; then
+ version=$2
+fi
+
+buildNodejsProject ${path} ${version}
diff --git a/codes/linux/soft/README.md b/codes/linux/soft/README.md
index 56deb72d..fd0010c5 100644
--- a/codes/linux/soft/README.md
+++ b/codes/linux/soft/README.md
@@ -13,7 +13,7 @@
- [RocketMQ 安装](#rocketmq-安装)
- [Nacos 安装](#nacos-安装)
- [ZooKeeper 安装](#zookeeper-安装)
-- [Nginx 安装](#nginx-安装)
+- [Nginx 运维](#nginx-安装)
- [Fastdfs 安装](#fastdfs-安装)
- [Docker 安装](#docker-安装)
@@ -29,7 +29,7 @@
执行以下任意命令即可执行安装脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/zsh-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/zsh-install.sh | bash
```
@@ -44,7 +44,7 @@ JDK8 会被安装到 `/usr/lib/jvm/java` 路径。
执行以下任意命令即可执行安装脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/jdk8-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/jdk8-install.sh | bash
```
@@ -60,7 +60,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/jd
执行以下任意命令即可执行安装脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/maven-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/maven-install.sh | bash
```
@@ -75,7 +75,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/ma
执行以下任意命令即可执行安装脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/nodejs-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/nodejs-install.sh | bash
```
@@ -90,43 +90,40 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/no
执行以下任意命令即可执行安装脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/mongodb-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/mongodb-install.sh | bash
```
## Redis 安装配置
-说明:
+**安装说明**
-- 下载 redis `5.0.4` 并解压安装到 `/opt/redis` 路径下。
-- 替换配置,使得 Redis 可以远程访问,并设置默认密码为 123456。
-- 注册 redis 服务,并设置为开机自启动
+- 采用编译方式安装 Redis, 并将其注册为 systemd 服务
+- 安装路径为:`/usr/local/redis`
+- 默认下载安装 `5.0.4` 版本,端口号为:`6379`,密码为空
-使用方法:
+**使用方法**
-执行以下任意命令即可按照默认配置安装脚本。
+- 默认安装 - 执行以下任意命令即可:
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/redis-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/redis-install.sh | bash
```
-定制化配置
+- 自定义安装 - 下载脚本到本地,并按照以下格式执行:
+
-```sh
-# 下载脚本到本地
-wget https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/redis-install.sh
-chmod +x redis-install.sh
-./redis-install.sh 5.0.4 /opt/redis 6379 123456
+```shell
+sh redis-install.sh [version] [port] [password]
```
-说明:
+参数说明:
-- 第一个参数是 redis 版本号;
-- 第二个参数是 redis 安装路径;
-- 第三个参数是 redis 服务端口号;
-- 第四个参数是访问密码
+- `version` - redis 版本号
+- `port` - redis 服务端口号
+- `password` - 访问密码
## Tomcat8 安装
@@ -136,7 +133,7 @@ chmod +x redis-install.sh
使用方法:
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/tomcat8-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/tomcat8-install.sh | bash
```
@@ -149,7 +146,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/to
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/kafka-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/kafka-install.sh | bash
```
@@ -162,7 +159,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/ka
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/rocketmq-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/rocketmq-install.sh | bash
```
@@ -175,7 +172,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/ro
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/nacos-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/nacos-install.sh | bash
```
@@ -188,26 +185,35 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/na
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/zookeeper-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/zookeeper-install.sh | bash
```
-## Nginx 安装
+## Nginx 运维
-说明:
+**安装说明**
-采用编译方式安装 Nginx
+- 采用编译方式安装 Nginx, 并将其注册为 systemd 服务
+- 安装路径为:`/usr/local/nginx`
+- 默认下载安装 `1.16.0` 版本
-下载 nginx `1.16.0` 并解压安装到 `/opt/nginx` 路径下。
+**使用方法**
+
+- 默认安装 - 执行以下任意命令即可:
-使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/nginx-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/nginx-install.sh | bash
```
+- 自定义安装 - 下载脚本到本地,并按照以下格式执行:
+
+```bash
+sh nginx-install.sh [version]
+```
+
## Fastdfs 安装
说明:
@@ -218,7 +224,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/ng
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/fastdfs-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/fastdfs-install.sh | bash
```
@@ -229,7 +235,18 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/fa
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/docker-install.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/docker-install.sh | bash
```
+
+## FastDFS 安装
+
+说明:
+
+使用方法:执行以下任意命令即可执行脚本。
+
+```shell
+curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/fastdfs-install.sh | bash
+wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/fastdfs-install.sh | bash
+```
diff --git a/codes/linux/soft/arthas-install.sh b/codes/linux/soft/arthas-install.sh
new file mode 100644
index 00000000..0a08892e
--- /dev/null
+++ b/codes/linux/soft/arthas-install.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+
+# ----------------------------------------------------------------------------------
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+# ----------------------------------------------------------------------------------
+
+printf "${PURPLE}"
+cat << EOF
+# ----------------------------------------------------------------------------------
+# Arthas 安装脚本
+# @author: Zhang Peng
+# ----------------------------------------------------------------------------------
+EOF
+printf "${RESET}"
+
+printf "${BLUE}>>>>>>>> begin.\n${RESET}"
+
+root=/opt/arthas
+if [[ -n $1 ]]; then
+ root=$1
+fi
+
+mkdir -p ${root}
+curl -o ${root}/arthas-boot.jar https://alibaba.github.io/arthas/arthas-boot.jar
+
+printf "${GREEN}[OK]\n${RESET}"
+printf "${BLUE}<<<<<<<< end.\n${RESET}"
diff --git a/codes/linux/soft/config/mysql/my.cnf b/codes/linux/soft/config/mysql/my.cnf
new file mode 100644
index 00000000..aa72e8cd
--- /dev/null
+++ b/codes/linux/soft/config/mysql/my.cnf
@@ -0,0 +1,48 @@
+# -------------------------------------------------------------------------------
+# Mysql 基本配置模板
+# -------------------------------------------------------------------------------
+
+[mysqld]
+# GENERAL
+# -------------------------------------------------------------------------------
+server_id = 2
+datadir = /var/lib/mysql
+socket = /var/lib/mysql/mysql.sock
+pid_file = /var/lib/mysql/mysql.pid
+user = mysql
+port = 3306
+default_storage_engine = InnoDB
+default_time_zone = '+8:00'
+character_set_server = utf8mb4
+collation_server = utf8mb4_0900_ai_ci
+
+# LOG
+# -------------------------------------------------------------------------------
+log_error = /var/log/mysql/mysql.log
+slow_query_log = 1
+slow_query_log_file = /var/log/mysql/mysql_slow_query_log.log
+long_query_time = 3
+min_examined_row_limit = 100
+expire_logs_days = 7
+
+# InnoDB
+# -------------------------------------------------------------------------------
+innodb_buffer_pool_size = 4G
+innodb_log_file_size = 128M
+innodb_file_per_table = 1
+innodb_flush_method = O_DIRECT
+
+# MyIsam
+# -------------------------------------------------------------------------------
+key_buffer_size = 256M
+
+# OTHER
+# -------------------------------------------------------------------------------
+tmp_table_size = 32M
+max_heap_table_size = 32M
+max_connections = 10000
+open_files_limit = 65535
+
+[client]
+socket = /var/lib/mysql/mysql.sock
+port = 3306
diff --git a/codes/linux/soft/config/nginx/nginx.conf b/codes/linux/soft/config/nginx/nginx.conf
index 5e4d737f..00a389bf 100644
--- a/codes/linux/soft/config/nginx/nginx.conf
+++ b/codes/linux/soft/config/nginx/nginx.conf
@@ -1,36 +1,37 @@
-worker_processes 1;
+worker_processes 1;
-#error_log logs/error.log;
-#error_log logs/error.log notice;
-#error_log logs/error.log info;
-pid /usr/local/nginx/logs/nginx.pid;
+error_log logs/error.log;
+#error_log logs/error.log notice;
+#error_log logs/error.log info;
+pid /usr/local/nginx/logs/nginx.pid;
events {
- worker_connections 1024;
+ worker_connections 1024;
}
http {
- 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"';
- #access_log logs/nginx-http-access.log;
- sendfile on;
- rewrite_log on;
- keepalive_timeout 65;
-
- client_max_body_size 20m;
- client_body_buffer_size 128k;
-
- #common header set
- proxy_http_version 1.1;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
-
- include mime.types;
- include conf/*.conf;
+ include mime.types;
+ include conf.d/*.conf;
+
+ 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"';
+ #access_log logs/nginx-http-access.log;
+
+ sendfile on;
+ keepalive_timeout 65;
+
+ client_max_body_size 20m;
+ client_body_buffer_size 128k;
+
+ #common header set
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
}
diff --git a/codes/linux/soft/config/redis/cluster/27001/sentinel.conf b/codes/linux/soft/config/redis/cluster/27001/sentinel.conf
new file mode 100644
index 00000000..0b7a6f02
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/27001/sentinel.conf
@@ -0,0 +1,8 @@
+port 27001
+daemonize yes
+sentinel monitor redis-master 172.22.6.3 7001 2
+sentinel down-after-milliseconds redis-master 5000
+sentinel failover-timeout redis-master 900000
+sentinel parallel-syncs redis-master 1
+#sentinel auth-pass redis-master 123456
+logfile /usr/local/redis/conf/27001/27001.log
\ No newline at end of file
diff --git a/codes/linux/soft/config/redis/cluster/27002/sentinel.conf b/codes/linux/soft/config/redis/cluster/27002/sentinel.conf
new file mode 100644
index 00000000..d208d9e4
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/27002/sentinel.conf
@@ -0,0 +1,8 @@
+port 27002
+daemonize yes
+sentinel monitor redis-master 172.22.6.3 7002 2
+sentinel down-after-milliseconds redis-master 5000
+sentinel failover-timeout redis-master 900000
+sentinel parallel-syncs redis-master 1
+#sentinel auth-pass redis-master 123456
+logfile /usr/local/redis/conf/27002/27002.log
\ No newline at end of file
diff --git a/codes/linux/soft/config/redis/cluster/27003/sentinel.conf b/codes/linux/soft/config/redis/cluster/27003/sentinel.conf
new file mode 100644
index 00000000..c6d8588a
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/27003/sentinel.conf
@@ -0,0 +1,8 @@
+port 27003
+daemonize yes
+sentinel monitor redis-master 172.22.6.3 7003 2
+sentinel down-after-milliseconds redis-master 5000
+sentinel failover-timeout redis-master 900000
+sentinel parallel-syncs redis-master 1
+#sentinel auth-pass redis-master 123456
+logfile /usr/local/redis/conf/27003/27003.log
\ No newline at end of file
diff --git a/codes/linux/soft/config/redis/cluster/27004/sentinel.conf b/codes/linux/soft/config/redis/cluster/27004/sentinel.conf
new file mode 100644
index 00000000..39f10881
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/27004/sentinel.conf
@@ -0,0 +1,8 @@
+port 27004
+daemonize yes
+sentinel monitor redis-master 172.22.6.3 7007 2
+sentinel down-after-milliseconds redis-master 5000
+sentinel failover-timeout redis-master 900000
+sentinel parallel-syncs redis-master 1
+#sentinel auth-pass redis-master 123456
+logfile /usr/local/redis/conf/27004/27004.log
diff --git a/codes/linux/soft/config/redis/cluster/27005/sentinel.conf b/codes/linux/soft/config/redis/cluster/27005/sentinel.conf
new file mode 100644
index 00000000..a33aa836
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/27005/sentinel.conf
@@ -0,0 +1,8 @@
+port 27005
+daemonize yes
+sentinel monitor redis-master 172.22.6.3 7008 2
+sentinel down-after-milliseconds redis-master 5000
+sentinel failover-timeout redis-master 900000
+sentinel parallel-syncs redis-master 1
+#sentinel auth-pass redis-master 123456
+logfile /usr/local/redis/conf/27005/27005.log
diff --git a/codes/linux/soft/config/redis/cluster/27006/sentinel.conf b/codes/linux/soft/config/redis/cluster/27006/sentinel.conf
new file mode 100644
index 00000000..a006f15e
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/27006/sentinel.conf
@@ -0,0 +1,8 @@
+port 27006
+daemonize yes
+sentinel monitor redis-master 172.22.6.3 7009 2
+sentinel down-after-milliseconds redis-master 5000
+sentinel failover-timeout redis-master 900000
+sentinel parallel-syncs redis-master 1
+#sentinel auth-pass redis-master 123456
+logfile /usr/local/redis/conf/27006/27006.log
diff --git a/codes/linux/soft/config/redis/cluster/7001/redis.conf b/codes/linux/soft/config/redis/cluster/7001/redis.conf
new file mode 100644
index 00000000..34bd0216
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7001/redis.conf
@@ -0,0 +1,12 @@
+port 7001
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7001/7001.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7001
+pidfile /usr/local/redis/conf/7001/7001.pid
+logfile /usr/local/redis/conf/7001/7001.log
diff --git a/codes/linux/soft/config/redis/cluster/7002/redis.conf b/codes/linux/soft/config/redis/cluster/7002/redis.conf
new file mode 100644
index 00000000..5e7fbc0d
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7002/redis.conf
@@ -0,0 +1,12 @@
+port 7002
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7002/7002.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7002
+pidfile /usr/local/redis/conf/7002/7002.pid
+logfile /usr/local/redis/conf/7002/7002.log
diff --git a/codes/linux/soft/config/redis/cluster/7003/redis.conf b/codes/linux/soft/config/redis/cluster/7003/redis.conf
new file mode 100644
index 00000000..e87573dd
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7003/redis.conf
@@ -0,0 +1,12 @@
+port 7003
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7003/7003.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7003
+pidfile /usr/local/redis/conf/7003/7003.pid
+logfile /usr/local/redis/conf/7003/7003.log
diff --git a/codes/linux/soft/config/redis/cluster/7004/redis.conf b/codes/linux/soft/config/redis/cluster/7004/redis.conf
new file mode 100644
index 00000000..1b4d6089
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7004/redis.conf
@@ -0,0 +1,12 @@
+port 7004
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7004/7004.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7004
+pidfile /usr/local/redis/conf/7004/7004.pid
+logfile /usr/local/redis/conf/7004/7004.log
diff --git a/codes/linux/soft/config/redis/cluster/7005/redis.conf b/codes/linux/soft/config/redis/cluster/7005/redis.conf
new file mode 100644
index 00000000..d959a8d6
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7005/redis.conf
@@ -0,0 +1,12 @@
+port 7005
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7005/7005.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7005
+pidfile /usr/local/redis/conf/7005/7005.pid
+logfile /usr/local/redis/conf/7005/7005.log
diff --git a/codes/linux/soft/config/redis/cluster/7006/redis.conf b/codes/linux/soft/config/redis/cluster/7006/redis.conf
new file mode 100644
index 00000000..6fd2635d
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7006/redis.conf
@@ -0,0 +1,12 @@
+port 7006
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7006/7006.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7006
+pidfile /usr/local/redis/conf/7006/7006.pid
+logfile /usr/local/redis/conf/7006/7006.log
diff --git a/codes/linux/soft/config/redis/cluster/7007/redis.conf b/codes/linux/soft/config/redis/cluster/7007/redis.conf
new file mode 100644
index 00000000..5cd28edc
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7007/redis.conf
@@ -0,0 +1,12 @@
+port 7007
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7007/7007.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7007
+pidfile /usr/local/redis/conf/7007/7007.pid
+logfile /usr/local/redis/conf/7007/7007.log
diff --git a/codes/linux/soft/config/redis/cluster/7008/redis.conf b/codes/linux/soft/config/redis/cluster/7008/redis.conf
new file mode 100644
index 00000000..54efbd84
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7008/redis.conf
@@ -0,0 +1,12 @@
+port 7008
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7008/7008.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7008
+pidfile /usr/local/redis/conf/7008/7008.pid
+logfile /usr/local/redis/conf/7008/7008.log
diff --git a/codes/linux/soft/config/redis/cluster/7009/redis.conf b/codes/linux/soft/config/redis/cluster/7009/redis.conf
new file mode 100644
index 00000000..41bdc4cc
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7009/redis.conf
@@ -0,0 +1,12 @@
+port 7009
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7009/7009.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7009
+pidfile /usr/local/redis/conf/7009/7009.pid
+logfile /usr/local/redis/conf/7009/7009.log
diff --git a/codes/linux/soft/config/redis/cluster/7010/redis.conf b/codes/linux/soft/config/redis/cluster/7010/redis.conf
new file mode 100644
index 00000000..b3b73f3d
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7010/redis.conf
@@ -0,0 +1,12 @@
+port 7010
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7010/7010.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7010
+pidfile /usr/local/redis/conf/7010/7010.pid
+logfile /usr/local/redis/conf/7010/7010.log
diff --git a/codes/linux/soft/config/redis/cluster/7011/redis.conf b/codes/linux/soft/config/redis/cluster/7011/redis.conf
new file mode 100644
index 00000000..ad94ad02
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7011/redis.conf
@@ -0,0 +1,12 @@
+port 7011
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7011/7011.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7011
+pidfile /usr/local/redis/conf/7011/7011.pid
+logfile /usr/local/redis/conf/7011/7011.log
diff --git a/codes/linux/soft/config/redis/cluster/7012/redis.conf b/codes/linux/soft/config/redis/cluster/7012/redis.conf
new file mode 100644
index 00000000..8b97944c
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/7012/redis.conf
@@ -0,0 +1,12 @@
+port 7012
+bind 172.22.6.3
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7012/7012.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7012
+pidfile /usr/local/redis/conf/7012/7012.pid
+logfile /usr/local/redis/conf/7012/7012.log
diff --git a/codes/linux/soft/config/redis/cluster/README.md b/codes/linux/soft/config/redis/cluster/README.md
new file mode 100644
index 00000000..f6322417
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/README.md
@@ -0,0 +1,53 @@
+# Redis 集群配置
+
+## 使用方式
+
+集群拓扑:
+
+- 三主三从
+- 三哨兵
+
+启动方式:
+
+- 先执行 redis-cluster.sh,会自动根据 7001 ~ 7006 目录启动服务器,并将其配置为集群。
+- 再执行 start-sentinel.sh,会根据 27001 ~ 27003 目录启动哨兵,监听集群中的三个主节点。
+
+## 配置
+
+(1)集群服务器配置 redis.conf
+
+```
+port 7001
+bind 0.0.0.0
+daemonize yes
+
+cluster-enabled yes
+cluster-config-file /usr/local/redis/conf/7001/7001.conf
+cluster-node-timeout 10000
+
+appendonly yes
+dir /usr/local/redis/conf/7001
+pidfile /usr/local/redis/conf/7001/7001.pid
+logfile /usr/local/redis/conf/7001/7001.log
+```
+
+端口号、配置目录(`/usr/local/redis/conf`)根据实际情况修改。
+
+(2)哨兵服务器配置 sentinel.conf
+
+```
+port 27003
+daemonize yes
+sentinel monitor redis-master 172.22.6.3 7003 2
+sentinel down-after-milliseconds redis-master 5000
+sentinel failover-timeout redis-master 900000
+sentinel parallel-syncs redis-master 1
+#sentinel auth-pass redis-master 123456
+logfile /usr/local/redis/conf/27003/27003.log
+```
+
+端口号、配置目录(`/usr/local/redis/conf`)根据实际情况修改。
+
+最重要的配置在于:sentinel monitor redis-master 172.22.6.3 7003 2
+
+表示监听的服务器集群名叫 redis-master,当前哨兵监听的服务器节点是:172.22.6.3:7003,这个节点如果是主节点,一旦宕机,选举新的主节点,需要至少 2 个哨兵同意。
diff --git a/codes/linux/soft/config/redis/cluster/redis-cluster.sh b/codes/linux/soft/config/redis/cluster/redis-cluster.sh
new file mode 100644
index 00000000..07c44d74
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/redis-cluster.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+
+# Settings
+HOST="172.22.6.3"
+PORT=7000
+TIMEOUT=2000
+NODES=6
+REPLICAS=1
+ENDPORT=$((PORT+NODES))
+
+# You may want to put the above config parameters into config.sh in order to
+# override the defaults without modifying this script.
+
+if [[ -a config.sh ]]
+then
+ source "config.sh"
+fi
+
+if [[ "$1" == "create" ]]
+then
+ HOSTLIST=""
+ while [[ $((PORT < ENDPORT)) != "0" ]]; do
+ PORT=$((PORT+1))
+ HOSTLIST="$HOSTLIST $HOST:$PORT"
+ done
+ /opt/redis/src/redis-cli --cluster create ${HOSTLIST} --cluster-replicas ${REPLICAS}
+ exit 0
+fi
+
+if [[ "$1" == "start" ]]
+then
+ while [[ $((PORT < ENDPORT)) != "0" ]]; do
+ PORT=$((PORT+1))
+ echo "Starting $PORT"
+ /opt/redis/src/redis-server /usr/local/redis/conf/${PORT}/redis.conf
+ done
+ exit 0
+fi
+
+if [[ "$1" == "stop" ]]
+then
+ while [[ $((PORT < ENDPORT)) != "0" ]]; do
+ PORT=$((PORT+1))
+ echo "Stopping $PORT"
+ /opt/redis/src/redis-cli -p ${PORT} shutdown nosave
+ done
+ exit 0
+fi
+
+if [[ "$1" == "watch" ]]
+then
+ PORT=$((PORT+1))
+ while [ 1 ]; do
+ clear
+ date
+ /opt/redis/src/redis-cli -p ${PORT} cluster nodes | head -30
+ sleep 1
+ done
+ exit 0
+fi
+
+if [[ "$1" == "tail" ]]
+then
+ INSTANCE=$2
+ PORT=$((PORT+INSTANCE))
+ tail -f ${PORT}.log
+ exit 0
+fi
+
+if [[ "$1" == "call" ]]
+then
+ while [[ $((PORT < ENDPORT)) != "0" ]]; do
+ PORT=$((PORT+1))
+ /opt/redis/src/redis-cli -p ${PORT} $2 $3 $4 $5 $6 $7 $8 $9
+ done
+ exit 0
+fi
+
+if [[ "$1" == "clean" ]]
+then
+ rm -rf *.log
+ rm -rf appendonly*.aof
+ rm -rf dump*.rdb
+ rm -rf nodes*.conf
+ exit 0
+fi
+
+if [[ "$1" == "clean-logs" ]]
+then
+ rm -rf *.log
+ exit 0
+fi
+
+echo "Usage: $0 [start|create|stop|watch|tail|clean]"
+echo "start -- Launch Redis Cluster instances."
+echo "create -- Create a cluster using redis-cli --cluster create."
+echo "stop -- Stop Redis Cluster instances."
+echo "watch -- Show CLUSTER NODES output (first 30 lines) of first node."
+echo "tail -- Run tail -f of instance at base port + ID."
+echo "clean -- Remove all instances data, logs, configs."
+echo "clean-logs -- Remove just instances logs."
diff --git a/codes/linux/soft/config/redis/cluster/redis-cluster2.sh b/codes/linux/soft/config/redis/cluster/redis-cluster2.sh
new file mode 100644
index 00000000..3e3b37e3
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/redis-cluster2.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+
+# Settings
+HOST="172.22.6.3"
+PORT=7000
+TIMEOUT=2000
+NODES=12
+REPLICAS=1
+ENDPORT=$((PORT+NODES))
+
+# You may want to put the above config parameters into config.sh in order to
+# override the defaults without modifying this script.
+
+if [[ -a config.sh ]]
+then
+ source "config.sh"
+fi
+
+if [[ "$1" == "create" ]]
+then
+ HOSTLIST=""
+ while [[ $((PORT < ENDPORT)) != "0" ]]; do
+ PORT=$((PORT+1))
+ HOSTLIST="$HOSTLIST $HOST:$PORT"
+ done
+ /opt/redis/src/redis-cli --cluster create ${HOSTLIST} --cluster-replicas ${REPLICAS}
+ exit 0
+fi
+
+if [[ "$1" == "start" ]]
+then
+ while [[ $((PORT < ENDPORT)) != "0" ]]; do
+ PORT=$((PORT+1))
+ echo "Starting $PORT"
+ /opt/redis/src/redis-server /usr/local/redis/conf/${PORT}/redis.conf
+ done
+ exit 0
+fi
+
+if [[ "$1" == "stop" ]]
+then
+ while [[ $((PORT < ENDPORT)) != "0" ]]; do
+ PORT=$((PORT+1))
+ echo "Stopping $PORT"
+ /opt/redis/src/redis-cli -p ${PORT} shutdown nosave
+ done
+ exit 0
+fi
+
+if [[ "$1" == "watch" ]]
+then
+ PORT=$((PORT+1))
+ while [ 1 ]; do
+ clear
+ date
+ /opt/redis/src/redis-cli -p ${PORT} cluster nodes | head -30
+ sleep 1
+ done
+ exit 0
+fi
+
+if [[ "$1" == "tail" ]]
+then
+ INSTANCE=$2
+ PORT=$((PORT+INSTANCE))
+ tail -f ${PORT}.log
+ exit 0
+fi
+
+if [[ "$1" == "call" ]]
+then
+ while [[ $((PORT < ENDPORT)) != "0" ]]; do
+ PORT=$((PORT+1))
+ /opt/redis/src/redis-cli -p ${PORT} $2 $3 $4 $5 $6 $7 $8 $9
+ done
+ exit 0
+fi
+
+if [[ "$1" == "clean" ]]
+then
+ rm -rf *.log
+ rm -rf appendonly*.aof
+ rm -rf dump*.rdb
+ rm -rf nodes*.conf
+ exit 0
+fi
+
+if [[ "$1" == "clean-logs" ]]
+then
+ rm -rf *.log
+ exit 0
+fi
+
+echo "Usage: $0 [start|create|stop|watch|tail|clean]"
+echo "start -- Launch Redis Cluster instances."
+echo "create -- Create a cluster using redis-cli --cluster create."
+echo "stop -- Stop Redis Cluster instances."
+echo "watch -- Show CLUSTER NODES output (first 30 lines) of first node."
+echo "tail -- Run tail -f of instance at base port + ID."
+echo "clean -- Remove all instances data, logs, configs."
+echo "clean-logs -- Remove just instances logs."
diff --git a/codes/linux/soft/config/redis/cluster/start-cluster.sh b/codes/linux/soft/config/redis/cluster/start-cluster.sh
new file mode 100644
index 00000000..c9ec4bea
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/start-cluster.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+PORT=6380
+NODES=6
+ENDPORT=$((PORT+NODES))
+
+# 启动 4 个 redis server
+while [[ $((PORT < ENDPORT)) != "0" ]]; do
+ PORT=$((PORT+1))
+ echo "Starting $PORT"
+ /opt/redis/src/redis-server /usr/local/redis/conf/${PORT}/redis.conf
+done
+
+# 创建集群模式,设置副本为 1
+# redis cluster 会自动将 4 个节点设置为 一主一从 模式,并且为两个主节点做数据分片
+/opt/redis/src/redis-cli --cluster create 172.22.6.3:6381 172.22.6.3:6382 172.22.6.3:6383 172.22.6.3:6384 172.22.6.3:6385 172.22.6.3:6386 --cluster-replicas 1
+
+# 启动哨兵
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/26381/sentinel.conf
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/26382/sentinel.conf
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/26383/sentinel.conf
diff --git a/codes/linux/soft/config/redis/cluster/start-cluster2.sh b/codes/linux/soft/config/redis/cluster/start-cluster2.sh
new file mode 100644
index 00000000..54b59c96
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/start-cluster2.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+# 启动 4 个 redis server
+/opt/redis/src/redis-server /usr/local/redis/conf/6381/redis.conf
+/opt/redis/src/redis-server /usr/local/redis/conf/6382/redis.conf
+/opt/redis/src/redis-server /usr/local/redis/conf/6383/redis.conf
+/opt/redis/src/redis-server /usr/local/redis/conf/6384/redis.conf
+/opt/redis/src/redis-server /usr/local/redis/conf/6385/redis.conf
+/opt/redis/src/redis-server /usr/local/redis/conf/6386/redis.conf
+
+# 创建集群模式,设置副本为 1
+# redis cluster 会自动将 4 个节点设置为 一主一从 模式,并且为两个主节点做数据分片
+/opt/redis/src/redis-cli --cluster create 172.22.6.3:6381 172.22.6.3:6382 172.22.6.3:6383 172.22.6.3:6384 172.22.6.3:6385 172.22.6.3:6386 --cluster-replicas 1
+
+# 启动哨兵
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/26381/sentinel.conf
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/26382/sentinel.conf
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/26383/sentinel.conf
diff --git a/codes/linux/soft/config/redis/cluster/start-sentinel.sh b/codes/linux/soft/config/redis/cluster/start-sentinel.sh
new file mode 100644
index 00000000..a21c7d63
--- /dev/null
+++ b/codes/linux/soft/config/redis/cluster/start-sentinel.sh
@@ -0,0 +1,6 @@
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/27001/sentinel.conf
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/27002/sentinel.conf
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/27003/sentinel.conf
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/27004/sentinel.conf
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/27005/sentinel.conf
+/opt/redis/src/redis-sentinel /usr/local/redis/conf/27006/sentinel.conf
diff --git a/codes/linux/soft/config/redis-remote-access.conf b/codes/linux/soft/config/redis/redis.conf
similarity index 99%
rename from codes/linux/soft/config/redis-remote-access.conf
rename to codes/linux/soft/config/redis/redis.conf
index 9744238a..90628501 100644
--- a/codes/linux/soft/config/redis-remote-access.conf
+++ b/codes/linux/soft/config/redis/redis.conf
@@ -66,7 +66,7 @@
# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES
# JUST COMMENT THE FOLLOWING LINE.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# bind 127.0.0.1
+bind 172.22.6.3
# Protected mode is a layer of security protection, in order to avoid that
# Redis instances left open on the internet are accessed and exploited.
@@ -85,7 +85,7 @@
# you are sure you want clients from other hosts to connect to Redis
# even if no authentication is configured, nor a specific set of interfaces
# are explicitly listed using the "bind" directive.
-protected-mode yes
+protected-mode no
# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
@@ -155,7 +155,7 @@ supervised no
#
# Creating a pid file is best effort: if Redis is not able to create it
# nothing bad happens, the server will start and run normally.
-pidfile /var/run/redis_6379.pid
+pidfile /var/run/redis/redis-6379.pid
# Specify the server verbosity level.
# This can be one of:
@@ -499,12 +499,12 @@ replica-priority 100
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
-#
+#:q
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
-requirepass 123456
+# requirepass
# Command renaming.
#
diff --git a/codes/linux/soft/config/redis/redis.service b/codes/linux/soft/config/redis/redis.service
new file mode 100644
index 00000000..53825745
--- /dev/null
+++ b/codes/linux/soft/config/redis/redis.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Redis
+After=network.target
+
+[Service]
+Type=forking
+PIDFile=/var/run/redis/redis-6379.pid
+ExecStart=/usr/local/bin/redis-server /usr/local/redis/redis.conf
+ExecReload=/bin/kill -s HUP $MAINPID
+ExecStop=/bin/kill -s QUIT $MAINPID
+PrivateTmp=true
+
+[Install]
+WantedBy=multi-user.target
diff --git a/codes/linux/soft/config/settings-aliyun.xml b/codes/linux/soft/config/settings-aliyun.xml
index a996086e..482173f2 100644
--- a/codes/linux/soft/config/settings-aliyun.xml
+++ b/codes/linux/soft/config/settings-aliyun.xml
@@ -1,21 +1,22 @@
-
+
-
-
-
- aliyun
- Aliyun
- http://maven.aliyun.com/nexus/content/groups/public
- central
-
-
- repo2
- Mirror from Maven Repo2
- http://repo2.maven.org/maven2/
- central
-
-
-
\ No newline at end of file
+
+
+
+ aliyun
+ Aliyun
+ http://maven.aliyun.com/nexus/content/groups/public
+ central
+
+
+ repo2
+ Mirror from Maven Repo2
+ http://repo2.maven.org/maven2/
+ central
+
+
+
diff --git a/codes/linux/soft/docker-install.sh b/codes/linux/soft/docker-install.sh
index 93056976..8907e749 100644
--- a/codes/linux/soft/docker-install.sh
+++ b/codes/linux/soft/docker-install.sh
@@ -27,22 +27,36 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install docker begin.${RESET}\n"
# uninstall old version docker
sudo yum remove docker \
- docker-client \
- docker-client-latest \
- docker-common \
- docker-latest \
- docker-latest-logrotate \
- docker-logrotate \
- docker-selinux \
- docker-engine-selinux \
- docker-engine
+ docker-client \
+ docker-client-latest \
+ docker-common \
+ docker-latest \
+ docker-latest-logrotate \
+ docker-logrotate \
+ docker-engine
+
# install required libs
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# add docker yum repo
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum makecache fast
# install docker
-sudo yum -y install docker-ce
+sudo yum install docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
docker version
printf "${GREEN}<<<<<<<< install docker end.${RESET}\n"
+
+printf "${GREEN}>>>>>>>> replace chinese docker mirror registry${RESET}\n"
+if [[ -f "/etc/docker/daemon.json" ]]; then
+ mv /etc/docker/daemon.json /etc/docker/daemon.json.bak
+else
+ mkdir -p /etc/docker
+fi
+touch /etc/docker/daemon.json
+cat >> /etc/docker/daemon.json << EOF
+{
+ "registry-mirrors": ["https://hub-mirror.c.163.com"]
+}
+EOF
+systemctl daemon-reload
+systemctl restart docker
diff --git a/codes/linux/soft/elk/boot-elk.sh b/codes/linux/soft/elk/boot-elk.sh
index 31ee08fa..52fed31f 100644
--- a/codes/linux/soft/elk/boot-elk.sh
+++ b/codes/linux/soft/elk/boot-elk.sh
@@ -2,50 +2,50 @@
# 检查脚本输入参数
checkInput() {
- if [ "${app}" == "" ] || [ "${oper}" == "" ]; then
- echo "请输入脚本参数:name"
- echo " app: 要启动的进程关键字(必填)。可选值:elasticsearch|logstash|kibana|filebeat"
- echo " oper: 执行操作(必填)。可选值:start|stop"
- echo "例:./boot-elk.sh logstash start"
- exit 0
- fi
+ if [ "${app}" == "" ] || [ "${oper}" == "" ]; then
+ echo "请输入脚本参数:name"
+ echo " app: 要启动的进程关键字(必填)。可选值:elasticsearch|logstash|kibana|filebeat"
+ echo " oper: 执行操作(必填)。可选值:start|stop"
+ echo "例:./boot-elk.sh logstash start"
+ exit 0
+ fi
- if [ "${app}" != "elasticsearch" ] && [ "${app}" != "logstash" ] && [ "${app}" != "kibana" ] && [ "${app}" != "filebeat" ]; then
- echo "name 输入错误"
- echo "可选值:elasticsearch|logstash|kibana|filebeat"
- exit 0
- fi
+ if [ "${app}" != "elasticsearch" ] && [ "${app}" != "logstash" ] && [ "${app}" != "kibana" ] && [ "${app}" != "filebeat" ]; then
+ echo "name 输入错误"
+ echo "可选值:elasticsearch|logstash|kibana|filebeat"
+ exit 0
+ fi
}
# 检查文件是否存在,不存在则退出脚本
checkFileExist() {
- if [ ! -f "$1" ]
- then
- echo "关键文件 $1 找不到,脚本执行结束"
- exit 0
- fi
+ if [ ! -f "$1" ]
+ then
+ echo "关键文件 $1 找不到,脚本执行结束"
+ exit 0
+ fi
}
startup() {
- if [ "${app}" == "elasticsearch" ]; then
- checkFileExist ${ELASTICSEARCH_BIN_PATH}/elasticsearch
- nohup sh ${ELASTICSEARCH_BIN_PATH}/elasticsearch >>${ELASTICSEARCH_BIN_PATH}/nohup.out 2>&1 &
- elif [ "${app}" == "logstash" ]; then
- checkFileExist ${LOGSTASH_BIN_PATH}/logstash
- nohup sh ${LOGSTASH_BIN_PATH}/logstash -f ${LOGSTASH_BIN_PATH}/logstash.conf >>${LOGSTASH_BIN_PATH}/nohup.out 2>&1 &
- elif [ "${app}" == "kibana" ]; then
- checkFileExist ${KIBANA_BIN_PATH}/kibana
- nohup sh ${KIBANA_BIN_PATH}/kibana >> ${KIBANA_BIN_PATH}/nohup.out 2>&1 &
- elif [ "${app}" == "filebeat" ]; then
- checkFileExist ${FILEBEAT_PATH}/filebeat
- touch ${FILEBEAT_PATH}/nohup.out
- nohup ${FILEBEAT_PATH}/filebeat -e -c ${FILEBEAT_PATH}/filebeat.yml -d "publish" >> ${FILEBEAT_PATH}/nohup.out 2>&1 &
- fi
+ if [ "${app}" == "elasticsearch" ]; then
+ checkFileExist ${ELASTICSEARCH_BIN_PATH}/elasticsearch
+ nohup sh ${ELASTICSEARCH_BIN_PATH}/elasticsearch >> ${ELASTICSEARCH_BIN_PATH}/nohup.out 2>&1 &
+ elif [ "${app}" == "logstash" ]; then
+ checkFileExist ${LOGSTASH_BIN_PATH}/logstash
+ nohup sh ${LOGSTASH_BIN_PATH}/logstash -f ${LOGSTASH_BIN_PATH}/logstash.conf >> ${LOGSTASH_BIN_PATH}/nohup.out 2>&1 &
+ elif [ "${app}" == "kibana" ]; then
+ checkFileExist ${KIBANA_BIN_PATH}/kibana
+ nohup sh ${KIBANA_BIN_PATH}/kibana >> ${KIBANA_BIN_PATH}/nohup.out 2>&1 &
+ elif [ "${app}" == "filebeat" ]; then
+ checkFileExist ${FILEBEAT_PATH}/filebeat
+ touch ${FILEBEAT_PATH}/nohup.out
+ nohup ${FILEBEAT_PATH}/filebeat -e -c ${FILEBEAT_PATH}/filebeat.yml -d "publish" >> ${FILEBEAT_PATH}/nohup.out 2>&1 &
+ fi
}
shutdown() {
- pid=`ps -ef | grep java | grep ${app} | awk '{print $2}'`
- kill -9 ${pid}
+ pid=`ps -ef | grep java | grep ${app} | awk '{print $2}'`
+ kill -9 ${pid}
}
##############################__MAIN__########################################
@@ -60,14 +60,14 @@ FILEBEAT_PATH=/opt/elastic/filebeat-${version}-linux-x86_64
checkInput
case ${oper} in
- start)
- echo "启动 ${app}"
- startup
- ;;
- stop)
- echo "终止 ${app}"
- shutdown
- ;;
- * ) echo "${oper} is invalid oper";;
+ start)
+ echo "启动 ${app}"
+ startup
+ ;;
+ stop)
+ echo "终止 ${app}"
+ shutdown
+ ;;
+ *) echo "${oper} is invalid oper" ;;
esac
diff --git a/codes/linux/soft/elk/config/filebeat.yml b/codes/linux/soft/elk/config/filebeat.yml
index c11956c1..256854a7 100644
--- a/codes/linux/soft/elk/config/filebeat.yml
+++ b/codes/linux/soft/elk/config/filebeat.yml
@@ -14,74 +14,74 @@
filebeat.prospectors:
-# Each - is a prospector. Most options can be set at the prospector level, so
-# you can use different prospectors for various configurations.
-# Below are the prospector specific configurations.
+ # Each - is a prospector. Most options can be set at the prospector level, so
+ # you can use different prospectors for various configurations.
+ # Below are the prospector specific configurations.
-- type: log
+ - type: log
- # Change to true to enable this prospector configuration.
- enabled: true
+ # Change to true to enable this prospector configuration.
+ enabled: true
- # Paths that should be crawled and fetched. Glob based paths.
- paths:
- #- /var/log/*.log
- #- c:\programdata\elasticsearch\logs\*
- - /home/zp/log/*.log
+ # Paths that should be crawled and fetched. Glob based paths.
+ paths:
+ #- /var/log/*.log
+ #- c:\programdata\elasticsearch\logs\*
+ - /home/zp/log/*.log
- # Exclude lines. A list of regular expressions to match. It drops the lines that are
- # matching any regular expression from the list.
- #exclude_lines: ['^DBG']
+ # Exclude lines. A list of regular expressions to match. It drops the lines that are
+ # matching any regular expression from the list.
+ #exclude_lines: ['^DBG']
- # Include lines. A list of regular expressions to match. It exports the lines that are
- # matching any regular expression from the list.
- #include_lines: ['^ERR', '^WARN']
+ # Include lines. A list of regular expressions to match. It exports the lines that are
+ # matching any regular expression from the list.
+ #include_lines: ['^ERR', '^WARN']
- # Exclude files. A list of regular expressions to match. Filebeat drops the files that
- # are matching any regular expression from the list. By default, no files are dropped.
- #exclude_files: ['.gz$']
+ # Exclude files. A list of regular expressions to match. Filebeat drops the files that
+ # are matching any regular expression from the list. By default, no files are dropped.
+ #exclude_files: ['.gz$']
- # Optional additional fields. These fields can be freely picked
- # to add additional information to the crawled log files for filtering
- #fields:
- # level: debug
- # review: 1
+ # Optional additional fields. These fields can be freely picked
+ # to add additional information to the crawled log files for filtering
+ #fields:
+ # level: debug
+ # review: 1
- ### Multiline options
+ ### Multiline options
- # Mutiline can be used for log messages spanning multiple lines. This is common
- # for Java Stack Traces or C-Line Continuation
+ # Mutiline can be used for log messages spanning multiple lines. This is common
+ # for Java Stack Traces or C-Line Continuation
- # The regexp Pattern that has to be matched. The example pattern matches all lines starting with [
- #multiline.pattern: ^\[
+ # The regexp Pattern that has to be matched. The example pattern matches all lines starting with [
+ #multiline.pattern: ^\[
- # Defines if the pattern set under pattern should be negated or not. Default is false.
- #multiline.negate: false
+ # Defines if the pattern set under pattern should be negated or not. Default is false.
+ #multiline.negate: false
- # Match can be set to "after" or "before". It is used to define if lines should be append to a pattern
- # that was (not) matched before or after or as long as a pattern is not matched based on negate.
- # Note: After is the equivalent to previous and before is the equivalent to to next in Logstash
- #multiline.match: after
+ # Match can be set to "after" or "before". It is used to define if lines should be append to a pattern
+ # that was (not) matched before or after or as long as a pattern is not matched based on negate.
+ # Note: After is the equivalent to previous and before is the equivalent to to next in Logstash
+ #multiline.match: after
#============================= Filebeat modules ===============================
filebeat.config.modules:
- # Glob pattern for configuration loading
- path: ${path.config}/modules.d/*.yml
+ # Glob pattern for configuration loading
+ path: ${path.config}/modules.d/*.yml
- # Set to true to enable config reloading
- reload.enabled: true
+ # Set to true to enable config reloading
+ reload.enabled: true
- # Period on which files under path should be checked for changes
- #reload.period: 10s
+ # Period on which files under path should be checked for changes
+ #reload.period: 10s
#==================== Elasticsearch template setting ==========================
setup.template.settings:
- index.number_of_shards: 3
- #index.codec: best_compression
- #_source.enabled: false
+ index.number_of_shards: 3
+ #index.codec: best_compression
+ #_source.enabled: false
#================================ General =====================================
@@ -96,7 +96,7 @@ name: 127.0.0.1
# Optional fields that you can specify to add additional information to the
# output.
fields:
- profile: development
+ profile: development
#============================== Dashboards =====================================
@@ -117,53 +117,53 @@ setup.dashboards.enabled: true
# This requires a Kibana endpoint configuration.
setup.kibana:
- # Kibana Host
- # Scheme and port can be left out and will be set to the default (http and 5601)
- # In case you specify and additional path, the scheme is required: http://localhost:5601/path
- # IPv6 addresses should always be defined as: https://[2001:db8::1]:5601
- host: "192.168.28.11:5601"
+ # Kibana Host
+ # Scheme and port can be left out and will be set to the default (http and 5601)
+ # In case you specify and additional path, the scheme is required: http://localhost:5601/path
+ # IPv6 addresses should always be defined as: https://[2001:db8::1]:5601
+ host: "192.168.28.11:5601"
-#============================= Elastic Cloud ==================================
+ #============================= Elastic Cloud ==================================
-# These settings simplify using filebeat with the Elastic Cloud (https://cloud.elastic.co/).
+ # These settings simplify using filebeat with the Elastic Cloud (https://cloud.elastic.co/).
-# The cloud.id setting overwrites the `output.elasticsearch.hosts` and
-# `setup.kibana.host` options.
-# You can find the `cloud.id` in the Elastic Cloud web UI.
-#cloud.id:
+ # The cloud.id setting overwrites the `output.elasticsearch.hosts` and
+ # `setup.kibana.host` options.
+ # You can find the `cloud.id` in the Elastic Cloud web UI.
+ #cloud.id:
-# The cloud.auth setting overwrites the `output.elasticsearch.username` and
-# `output.elasticsearch.password` settings. The format is `:`.
-#cloud.auth:
+ # The cloud.auth setting overwrites the `output.elasticsearch.username` and
+ # `output.elasticsearch.password` settings. The format is `:`.
+ #cloud.auth:
-#================================ Outputs =====================================
+ #================================ Outputs =====================================
-# Configure what output to use when sending the data collected by the beat.
+ # Configure what output to use when sending the data collected by the beat.
-#-------------------------- Elasticsearch output ------------------------------
-#output.elasticsearch:
- # Array of hosts to connect to.
- #hosts: ["192.168.28.11:9200"]
+ #-------------------------- Elasticsearch output ------------------------------
+ #output.elasticsearch:
+ # Array of hosts to connect to.
+ #hosts: ["192.168.28.11:9200"]
- # Optional protocol and basic auth credentials.
- protocol: "http"
- #username: "elastic"
- #password: "changeme"
+ # Optional protocol and basic auth credentials.
+ protocol: "http"
+ #username: "elastic"
+ #password: "changeme"
#----------------------------- Logstash output --------------------------------
output.logstash:
- # The Logstash hosts
- hosts: ["192.168.28.32:5044"]
+ # The Logstash hosts
+ hosts: ["192.168.28.32:5044"]
- # Optional SSL. By default is off.
- # List of root certificates for HTTPS server verifications
- #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"]
+ # Optional SSL. By default is off.
+ # List of root certificates for HTTPS server verifications
+ #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"]
- # Certificate for SSL client authentication
- #ssl.certificate: "/etc/pki/client/cert.pem"
+ # Certificate for SSL client authentication
+ #ssl.certificate: "/etc/pki/client/cert.pem"
- # Client Certificate Key
- #ssl.key: "/etc/pki/client/cert.key"
+ # Client Certificate Key
+ #ssl.key: "/etc/pki/client/cert.key"
#================================ Logging =====================================
diff --git a/codes/linux/soft/elk/config/logback.xml b/codes/linux/soft/elk/config/logback.xml
index c86d34a2..bb45d085 100644
--- a/codes/linux/soft/elk/config/logback.xml
+++ b/codes/linux/soft/elk/config/logback.xml
@@ -3,55 +3,55 @@
-
-
-
-
-
- %d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
-
-
-
-
-
-
-
- ${user.dir}/logs/${FILE_NAME}-all.%d{yyyy-MM-dd}.log
- 30
-
-
-
-
- 30MB
-
-
-
- %d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
-
-
-
-
- 192.168.28.32:9251
-
- {"appname":"javatool"}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
+
+
+
+
+
+
+
+ ${user.dir}/logs/${FILE_NAME}-all.%d{yyyy-MM-dd}.log
+ 30
+
+
+
+
+ 30MB
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n
+
+
+
+
+ 192.168.28.32:9251
+
+ {"appname":"javatool"}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/codes/linux/soft/elk/install-elk.sh b/codes/linux/soft/elk/install-elk.sh
index 87519603..eb96cb74 100644
--- a/codes/linux/soft/elk/install-elk.sh
+++ b/codes/linux/soft/elk/install-elk.sh
@@ -9,98 +9,99 @@
# 获取当前设备IP
ipaddr='127.0.0.1'
function getDeviceIp() {
- ipaddr=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
+ ipaddr=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
}
# 检查文件是否存在,不存在则退出脚本
checkFileExist() {
- if [ ! -f "$1" ]
- then
- echo "关键文件 $1 找不到,脚本执行结束"
- exit 0
- fi
+ if [ ! -f "$1" ]
+ then
+ echo "关键文件 $1 找不到,脚本执行结束"
+ exit 0
+ fi
}
init() {
- mkdir -p ${ELASTIC_SOFTWARE_PATH}
- getDeviceIp
+ mkdir -p ${ELASTIC_SOFTWARE_PATH}
+ getDeviceIp
}
# 安装 elasticsearch
installElasticsearch() {
- cd ${ELASTIC_SOFTWARE_PATH}
- wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${version}.tar.gz
- tar -xzf elasticsearch-${version}.tar.gz
+ cd ${ELASTIC_SOFTWARE_PATH}
+ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${version}.tar.gz
+ tar -xzf elasticsearch-${version}.tar.gz
}
installRuby() {
- cd ${RUBY_SOFTWARE_PATH}
- wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.0.tar.gz
- tar -xzf ruby-2.5.0.tar.gz
- cd ruby-2.5.0
- ./configure
- make & make install
+ cd ${RUBY_SOFTWARE_PATH}
+ wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.0.tar.gz
+ tar -xzf ruby-2.5.0.tar.gz
+ cd ruby-2.5.0
+ ./configure
+ make & make install
}
# 安装 logstash
installLogstash() {
- cd ${ELASTIC_SOFTWARE_PATH}
- wget https://artifacts.elastic.co/downloads/logstash/logstash-${version}.tar.gz
- tar -xzf logstash-${version}.tar.gz
+ cd ${ELASTIC_SOFTWARE_PATH}
+ wget https://artifacts.elastic.co/downloads/logstash/logstash-${version}.tar.gz
+ tar -xzf logstash-${version}.tar.gz
}
# 安装 kibana
installKibana() {
- cd ${ELASTIC_SOFTWARE_PATH}
- wget https://artifacts.elastic.co/downloads/kibana/kibana-${version}-linux-x86_64.tar.gz
- tar -xzf kibana-${version}-linux-x86_64.tar.gz
+ cd ${ELASTIC_SOFTWARE_PATH}
+ wget https://artifacts.elastic.co/downloads/kibana/kibana-${version}-linux-x86_64.tar.gz
+ tar -xzf kibana-${version}-linux-x86_64.tar.gz
}
# 安装 filebeat
installFilebeat() {
- cd ${ELASTIC_SOFTWARE_PATH}
- wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-${version}-linux-x86_64.tar.gz
- tar -zxf filebeat-${version}-linux-x86_64.tar.gz
+ cd ${ELASTIC_SOFTWARE_PATH}
+ wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-${version}-linux-x86_64.tar.gz
+ tar -zxf filebeat-${version}-linux-x86_64.tar.gz
}
# 替换 Elasticsearch 配置
# 1. 替换 192.168.0.1 为本机 IP
replaceElasticsearchConfig() {
- cp ${ELASTIC_SOFTWARE_PATH}/elasticsearch-${version}/config/elasticsearch.yml ${ELASTIC_SOFTWARE_PATH}/elasticsearch-${version}/config/elasticsearch.yml.bak
- sed -i "s/#network.host: 192.168.0.1/network.host: ${IP}/g" ${ELASTIC_SOFTWARE_PATH}/elasticsearch-${version}/config/elasticsearch.yml
- touch ${ELASTIC_SOFTWARE_PATH}/elasticsearch-${version}/bin/nohup.out
+ cp ${ELASTIC_SOFTWARE_PATH}/elasticsearch-${version}/config/elasticsearch.yml ${ELASTIC_SOFTWARE_PATH}/elasticsearch-${version}/config/elasticsearch.yml.bak
+ sed -i "s/#network.host: 192.168.0.1/network.host: ${IP}/g" ${ELASTIC_SOFTWARE_PATH}/elasticsearch-${version}/config/elasticsearch.yml
+ touch ${ELASTIC_SOFTWARE_PATH}/elasticsearch-${version}/bin/nohup.out
}
replaceLogstashConfig() {
- cp ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/config/logstash.yml ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/config/logstash.yml.bak
- sed -i "s/# http.host: \"127.0.0.1\"/ http.host: ${IP}/g" ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/config/logstash.yml
- touch ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/bin/nohup.out
- cd ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/bin
- wget "https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/elk/config/logstash.conf"
+ cp ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/config/logstash.yml ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/config/logstash.yml.bak
+ sed -i "s/# http.host: \"127.0.0.1\"/ http.host: ${IP}/g" ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/config/logstash.yml
+ touch ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/bin/nohup.out
+ cd ${ELASTIC_SOFTWARE_PATH}/logstash-${version}/bin
+ wget "https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/elk/config/logstash.conf"
}
# 替换 Kibana 配置
# 1. 替换 localhost 为本机 IP
replaceKibanaConfig() {
- cp ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/config/kibana.yml ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/config/kibana.yml.bak
- sed -i "s/#server.host: \"localhost\"/server.host: ${IP}/g" ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/config/kibana.yml
- sed -i "s/#elasticsearch.url: \"http://localhost:9200\"/#elasticsearch.url: \"${IP}\"/g" ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/config/kibana.yml
- touch ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/bin/nohup.out
+ cp ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/config/kibana.yml ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/config/kibana.yml.bak
+ sed -i "s/#server.host: \"localhost\"/server.host: ${IP}/g" ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/config/kibana.yml
+ sed -i "s/#elasticsearch.url: \"http://localhost:9200\"/#elasticsearch.url: \"${IP}\"/g" ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/config/kibana.yml
+ touch ${ELASTIC_SOFTWARE_PATH}/kibana-${version}-linux-x86_64/bin/nohup.out
}
# 替换 Filebeat 配置
replaceFilebeatConfig() {
- cp ${ELASTIC_SOFTWARE_PATH}/filebeat-${version}-linux-x86_64/filebeat.yml ${ELASTIC_SOFTWARE_PATH}/filebeat-${version}-linux-x86_64/filebeat.yml.bak
- cd ${ELASTIC_SOFTWARE_PATH}/filebeat-${version}-linux-x86_64
- wget https://github.com/dunwu/OS/blob/master/codes/deploy/tool/elk/config/filebeat.yml
- sed -i 's/127.0.0.1/'"${IP}"'/g' ${ELASTIC_SOFTWARE_PATH}/filebeat-${version}-linux-x86_64/filebeat.yml
+ cp ${ELASTIC_SOFTWARE_PATH}/filebeat-${version}-linux-x86_64/filebeat.yml ${ELASTIC_SOFTWARE_PATH}/filebeat-${version}-linux-x86_64/filebeat.yml.bak
+ cd ${ELASTIC_SOFTWARE_PATH}/filebeat-${version}-linux-x86_64
+ wget https://github.com/dunwu/OS/blob/master/codes/deploy/tool/elk/config/filebeat.yml
+ sed -i 's/127.0.0.1/'"${IP}"'/g' ${ELASTIC_SOFTWARE_PATH}/filebeat-${version}-linux-x86_64/filebeat.yml
}
# 为 elk.elk 用户设置权限
setPrivilegeForUser() {
- chown -R elk.elk ${ELASTIC_SOFTWARE_PATH}
- chown -R elk.elk /var/log/
+ chown -R elk.elk ${ELASTIC_SOFTWARE_PATH}
+ chown -R elk.elk /var/log/
}
+
######################################## MAIN ########################################
echo -e "\n>>>>>>>>> install elk"
diff --git a/codes/linux/soft/elk/install_elasticserch.sh b/codes/linux/soft/elk/install_elasticserch.sh
index 95113905..bae8250f 100644
--- a/codes/linux/soft/elk/install_elasticserch.sh
+++ b/codes/linux/soft/elk/install_elasticserch.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# auth:kaliarch
# version:v1.0
# func:elasticsearch 5.4.1/6.0.1/6.3.1安装
@@ -12,9 +13,9 @@ env_file=/etc/profile.d/elasticsearch.sh
install_log_path=/var/log/appinstall/
install_path=/usr/local/
software_config_file=${install_path}elasticsearch/config/elasticsearch.yml
-sysversion=$(rpm -q centos-release|cut -d- -f3)
+sysversion=$(rpm -q centos-release | cut -d- -f3)
jvm_conf="/usr/local/elasticsearch/config/jvm.options"
-sys_mem=`free -m|grep Mem:|awk '{print $2}'|awk '{sum+=$1} END {print sum/1024}'|cut -d. -f1`
+sys_mem=`free -m | grep Mem: | awk '{print $2}' | awk '{sum+=$1} END {print sum/1024}' | cut -d. -f1`
hostname=elk-server
clear
@@ -29,114 +30,114 @@ echo "3: Install elasticsearch 6.3.1"
echo "4: EXIT"
# 选择安装软件版本
read -p "Please input your choice:" softversion
-if [ "${softversion}" == "1" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/elasticsearch/elasticsearch-5.4.1.tar.gz"
-elif [ "${softversion}" == "2" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/elasticsearch/elasticsearch-6.0.1.tar.gz"
-elif [ "${softversion}" == "3" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/elasticsearch/elasticsearch-6.3.1.tar.gz"
-elif [ "${softversion}" == "4" ];then
- echo "you choce channel!"
- exit 1;
+if [ "${softversion}" == "1" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/elasticsearch/elasticsearch-5.4.1.tar.gz"
+elif [ "${softversion}" == "2" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/elasticsearch/elasticsearch-6.0.1.tar.gz"
+elif [ "${softversion}" == "3" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/elasticsearch/elasticsearch-6.3.1.tar.gz"
+elif [ "${softversion}" == "4" ]; then
+ echo "you choce channel!"
+ exit 1;
else
- echo "input Error! Place input{1|2|3|4|5}"
- exit 0;
+ echo "input Error! Place input{1|2|3|4|5}"
+ exit 0;
fi
# 传入内容,格式化内容输出,可以传入多个参数,用空格隔开
output_msg() {
- for msg in $*;do
- action $msg /bin/true
- done
+ for msg in $*; do
+ action $msg /bin/true
+ done
}
# 判断命令是否存在,第一个参数 $1 为判断的命令,第二个参数为提供该命令的yum 软件包名称
check_yum_command() {
- output_msg "命令检查:$1"
- hash $1 >/dev/null 2>&1
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` check command $1 ">>${install_log_path}${install_log_name} && return 0
- else
- yum -y install $2 >/dev/null 2>&1
- # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
- fi
+ output_msg "命令检查:$1"
+ hash $1 > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` check command $1 " >> ${install_log_path}${install_log_name} && return 0
+ else
+ yum -y install $2 > /dev/null 2>&1
+ # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
+ fi
}
# 判断目录是否存在,传入目录绝对路径,可以传入多个目录
check_dir() {
- output_msg "目录检查"
- for dirname in $*;do
- [ -d $dirname ] || mkdir -p $dirname >/dev/null 2>&1
- echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
- done
+ output_msg "目录检查"
+ for dirname in $*; do
+ [ -d $dirname ] || mkdir -p $dirname > /dev/null 2>&1
+ echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
+ done
}
# 下载文件并解压至安装目录,传入url链接地址
download_file() {
- output_msg "下载源码包"
- mkdir -p $download_path
- for file in $*;do
- wget $file -c -P $download_path &> /dev/null
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` $file download success!">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%s` $file download fail!">>${install_log_path}${install_log_name} && exit 1
- fi
- done
+ output_msg "下载源码包"
+ mkdir -p $download_path
+ for file in $*; do
+ wget $file -c -P $download_path &> /dev/null
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` $file download success!" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%s` $file download fail!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ done
}
# 解压文件,可以传入多个压缩文件绝对路径,用空格隔开,解压至安装目录
extract_file() {
- output_msg "解压源码"
- for file in $*;do
- if [ "${file##*.}" == "gz" ];then
- tar -zxf $file -C $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path">>${install_log_path}${install_log_name}
- elif [ "${file##*.}" == "zip" ];then
- unzip -q $file -d $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%S` $file type error, extrac fail!">>${install_log_path}${install_log_name} && exit 1
- fi
- done
+ output_msg "解压源码"
+ for file in $*; do
+ if [ "${file##*.}" == "gz" ]; then
+ tar -zxf $file -C $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path" >> ${install_log_path}${install_log_name}
+ elif [ "${file##*.}" == "zip" ]; then
+ unzip -q $file -d $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%S` $file type error, extrac fail!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ done
}
# 配置环境变量,第一个参数为添加环境变量的绝对路径
config_env() {
- output_msg "环境变量配置"
-
- echo "export PATH=\$PATH:$1" >${env_file}
- source ${env_file} && echo "`date +%F' '%H:%M:%S` 软件安装完成!">> ${install_log_path}${install_log_name}
+ output_msg "环境变量配置"
+
+ echo "export PATH=\$PATH:$1" > ${env_file}
+ source ${env_file} && echo "`date +%F' '%H:%M:%S` 软件安装完成!" >> ${install_log_path}${install_log_name}
}
# 配置主机名,第一个为主机名
config_hostname() {
-if [ ${sysversion} -eq 6 ];then
- hostname $1
-elif [ ${sysversion} -eq 7 ];then
- hostnamectl set-hostname $1
-else
- echo "`date +%F' '%H:%M:%S` hostname $1 config fail">> ${install_log_path}${install_log_name}
-fi
+ if [ ${sysversion} -eq 6 ]; then
+ hostname $1
+ elif [ ${sysversion} -eq 7 ]; then
+ hostnamectl set-hostname $1
+ else
+ echo "`date +%F' '%H:%M:%S` hostname $1 config fail" >> ${install_log_path}${install_log_name}
+ fi
}
config_limits() {
- output_msg "配置limits"
- cat >>/etc/security/limits.conf<> /etc/security/limits.conf << EOF
+* soft nofile 65536
+* hard nofile 65536
+* soft nproc 65536
* hard nproc 65536
EOF
-echo "vm.max_map_count = 655360" >>/etc/sysctl.conf
-sysctl -p >/dev/null 2>&1
+ echo "vm.max_map_count = 655360" >> /etc/sysctl.conf
+ sysctl -p > /dev/null 2>&1
}
# 添加配置文件
add_config() {
-cat > $1 << EOF
+ cat > $1 << EOF
cluster.name: my-application
node.name: ${hostname}
path.data: /usr/local/elasticsearch/data
@@ -148,46 +149,46 @@ EOF
}
config_user() {
-useradd $1 >/dev/null 2>&1
-if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` $1 user add success">> ${install_log_path}${install_log_name}
-else
- echo "`date +%F' '%H:%M:%S` $1 user add fail">> ${install_log_path}${install_log_name} && exit 1
-fi
-chown ${1}.${1} ${install_path}elasticsearch/ -R
+ useradd $1 > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` $1 user add success" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%S` $1 user add fail" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ chown ${1}.${1} ${install_path}elasticsearch/ -R
}
config_jvm() {
-if [ ${sys_mem} -eq 0 ];then
- sed -i "s#`grep "^-Xmx" ${jvm_conf}`#"-Xmx512m"#g" ${jvm_conf}
- sed -i "s#`grep "^-Xms" ${jvm_conf}`#"-Xms512m"#g" ${jvm_conf}
-else
- sed -i "s#`grep "^-Xmx" ${jvm_conf}`#"-Xmx${sys_mem}g"#g" ${jvm_conf}
- sed -i "s#`grep "^-Xms" ${jvm_conf}`#"-Xms${sys_mem}g"#g" ${jvm_conf}
-fi
+ if [ ${sys_mem} -eq 0 ]; then
+ sed -i "s#`grep "^-Xmx" ${jvm_conf}`#"-Xmx512m"#g" ${jvm_conf}
+ sed -i "s#`grep "^-Xms" ${jvm_conf}`#"-Xms512m"#g" ${jvm_conf}
+ else
+ sed -i "s#`grep "^-Xmx" ${jvm_conf}`#"-Xmx${sys_mem}g"#g" ${jvm_conf}
+ sed -i "s#`grep "^-Xms" ${jvm_conf}`#"-Xms${sys_mem}g"#g" ${jvm_conf}
+ fi
}
main() {
-check_dir $install_log_path $install_path
-check_yum_command wget wget
-download_file $URL
-config_hostname $hostname
-
-software_name=$(echo $URL|awk -F'/' '{print $NF}'|awk -F'.tar.gz' '{print $1}')
-for filename in `ls $download_path`;do
- extract_file ${download_path}$filename
-done
-
-rm -fr ${download_path}
-ln -s $install_path$software_name ${install_path}elasticsearch
-add_config $software_config_file
-check_dir ${install_path}elasticsearch/{data,logs}
-config_user elasticsearch
-config_env ${install_path}elasticsearch/bin
-config_limits
-config_jvm
-echo "请使用一下命令启动服务:'su - elasticsearch -c 'nohup /usr/local/elasticsearch/bin/elasticsearch &'"
+ check_dir $install_log_path $install_path
+ check_yum_command wget wget
+ download_file $URL
+ config_hostname $hostname
+
+ software_name=$(echo $URL | awk -F'/' '{print $NF}' | awk -F'.tar.gz' '{print $1}')
+ for filename in `ls $download_path`; do
+ extract_file ${download_path}$filename
+ done
+
+ rm -fr ${download_path}
+ ln -s $install_path$software_name ${install_path}elasticsearch
+ add_config $software_config_file
+ check_dir ${install_path}elasticsearch/{data,logs}
+ config_user elasticsearch
+ config_env ${install_path}elasticsearch/bin
+ config_limits
+ config_jvm
+ echo "请使用一下命令启动服务:'su - elasticsearch -c 'nohup /usr/local/elasticsearch/bin/elasticsearch &'"
}
diff --git a/codes/linux/soft/elk/install_filebeat.sh b/codes/linux/soft/elk/install_filebeat.sh
index 6c09aec2..812f81ce 100644
--- a/codes/linux/soft/elk/install_filebeat.sh
+++ b/codes/linux/soft/elk/install_filebeat.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# auth:kaliarch
# version:v1.0
# func:filebeat 5.6.1/6.1.3/6.3.2 安装
@@ -26,89 +27,89 @@ echo "3: Install filebeat 6.3.2"
echo "4: EXIT"
# 选择安装软件版本
read -p "Please input your choice:" softversion
-if [ "${softversion}" == "1" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/filebeat/filebeat-5.6.1-linux-x86_64.tar.gz"
-elif [ "${softversion}" == "2" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/filebeat/filebeat-6.1.3-linux-x86_64.tar.gz"
-elif [ "${softversion}" == "3" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/filebeat/filebeat-6.3.2-linux-x86_64.tar.gz"
-elif [ "${softversion}" == "4" ];then
- echo "you choce channel!"
- exit 1;
+if [ "${softversion}" == "1" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/filebeat/filebeat-5.6.1-linux-x86_64.tar.gz"
+elif [ "${softversion}" == "2" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/filebeat/filebeat-6.1.3-linux-x86_64.tar.gz"
+elif [ "${softversion}" == "3" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/filebeat/filebeat-6.3.2-linux-x86_64.tar.gz"
+elif [ "${softversion}" == "4" ]; then
+ echo "you choce channel!"
+ exit 1;
else
- echo "input Error! Place input{1|2|3|4}"
- exit 0;
+ echo "input Error! Place input{1|2|3|4}"
+ exit 0;
fi
# 传入内容,格式化内容输出,可以传入多个参数,用空格隔开
output_msg() {
- for msg in $*;do
- action $msg /bin/true
- done
+ for msg in $*; do
+ action $msg /bin/true
+ done
}
# 判断命令是否存在,第一个参数 $1 为判断的命令,第二个参数为提供该命令的yum 软件包名称
check_yum_command() {
- output_msg "命令检查:$1"
- hash $1 >/dev/null 2>&1
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` check command $1 ">>${install_log_path}${install_log_name} && return 0
- else
- yum -y install $2 >/dev/null 2>&1
- # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
- fi
+ output_msg "命令检查:$1"
+ hash $1 > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` check command $1 " >> ${install_log_path}${install_log_name} && return 0
+ else
+ yum -y install $2 > /dev/null 2>&1
+ # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
+ fi
}
# 判断目录是否存在,传入目录绝对路径,可以传入多个目录
check_dir() {
- output_msg "目录检查"
- for dirname in $*;do
- [ -d $dirname ] || mkdir -p $dirname >/dev/null 2>&1
- echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
- done
+ output_msg "目录检查"
+ for dirname in $*; do
+ [ -d $dirname ] || mkdir -p $dirname > /dev/null 2>&1
+ echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
+ done
}
# 下载文件并解压至安装目录,传入url链接地址
download_file() {
- output_msg "下载源码包"
- mkdir -p $download_path
- for file in $*;do
- wget $file -c -P $download_path &> /dev/null
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` $file download success!">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%s` $file download fail!">>${install_log_path}${install_log_name} && exit 1
- fi
- done
+ output_msg "下载源码包"
+ mkdir -p $download_path
+ for file in $*; do
+ wget $file -c -P $download_path &> /dev/null
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` $file download success!" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%s` $file download fail!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ done
}
# 解压文件,可以传入多个压缩文件绝对路径,用空格隔开,解压至安装目录
extract_file() {
- output_msg "解压源码"
- for file in $*;do
- if [ "${file##*.}" == "gz" ];then
- tar -zxf $file -C $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path">>${install_log_path}${install_log_name}
- elif [ "${file##*.}" == "zip" ];then
- unzip -q $file -d $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%S` $file type error, extrac fail!">>${install_log_path}${install_log_name} && exit 1
- fi
- done
+ output_msg "解压源码"
+ for file in $*; do
+ if [ "${file##*.}" == "gz" ]; then
+ tar -zxf $file -C $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path" >> ${install_log_path}${install_log_name}
+ elif [ "${file##*.}" == "zip" ]; then
+ unzip -q $file -d $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%S` $file type error, extrac fail!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ done
}
# 配置环境变量,第一个参数为添加环境变量的绝对路径
config_env() {
- output_msg "环境变量配置"
- echo "export PATH=\$PATH:$1" >${env_file}
- source ${env_file} && echo "`date +%F' '%H:%M:%S` 软件安装完成!">> ${install_log_path}${install_log_name}
+ output_msg "环境变量配置"
+ echo "export PATH=\$PATH:$1" > ${env_file}
+ source ${env_file} && echo "`date +%F' '%H:%M:%S` 软件安装完成!" >> ${install_log_path}${install_log_name}
}
# 添加配置文件
add_config() {
-cat> $1 < $1 << EOF
filebeat.prospectors:
- input_type: log
paths:
@@ -119,17 +120,17 @@ EOF
}
main() {
-check_dir $install_log_path $install_path
-check_yum_command wget wget
-download_file $URL
-
-software_name=$(echo $URL|awk -F'/' '{print $NF}'|awk -F'.tar.gz' '{print $1}')
-for filename in `ls $download_path`;do
- extract_file ${download_path}$filename
-done
-rm -fr ${download_path}
-ln -s $install_path$software_name ${install_path}filebeat
-add_config ${software_config_file}
+ check_dir $install_log_path $install_path
+ check_yum_command wget wget
+ download_file $URL
+
+ software_name=$(echo $URL | awk -F'/' '{print $NF}' | awk -F'.tar.gz' '{print $1}')
+ for filename in `ls $download_path`; do
+ extract_file ${download_path}$filename
+ done
+ rm -fr ${download_path}
+ ln -s $install_path$software_name ${install_path}filebeat
+ add_config ${software_config_file}
}
main
diff --git a/codes/linux/soft/elk/install_kibana.sh b/codes/linux/soft/elk/install_kibana.sh
index 55325317..7e77ecb2 100644
--- a/codes/linux/soft/elk/install_kibana.sh
+++ b/codes/linux/soft/elk/install_kibana.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# auth:kaliarch
# version:v1.0
# func:kibana 6.0.1/6.2.4/6.3.1 安装
@@ -26,89 +27,89 @@ echo "3: Install kibana 6.3.1"
echo "4: EXIT"
# 选择安装软件版本
read -p "Please input your choice:" softversion
-if [ "${softversion}" == "1" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/kibana/kibana-6.0.1-linux-x86_64.tar.gz"
-elif [ "${softversion}" == "2" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/kibana/kibana-6.2.4-linux-x86_64.tar.gz"
-elif [ "${softversion}" == "3" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/kibana/kibana-6.3.1-linux-x86_64.tar.gz"
-elif [ "${softversion}" == "4" ];then
- echo "you choce channel!"
- exit 1;
+if [ "${softversion}" == "1" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/kibana/kibana-6.0.1-linux-x86_64.tar.gz"
+elif [ "${softversion}" == "2" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/kibana/kibana-6.2.4-linux-x86_64.tar.gz"
+elif [ "${softversion}" == "3" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/kibana/kibana-6.3.1-linux-x86_64.tar.gz"
+elif [ "${softversion}" == "4" ]; then
+ echo "you choce channel!"
+ exit 1;
else
- echo "input Error! Place input{1|2|3|4}"
- exit 0;
+ echo "input Error! Place input{1|2|3|4}"
+ exit 0;
fi
# 传入内容,格式化内容输出,可以传入多个参数,用空格隔开
output_msg() {
- for msg in $*;do
- action $msg /bin/true
- done
+ for msg in $*; do
+ action $msg /bin/true
+ done
}
# 判断命令是否存在,第一个参数 $1 为判断的命令,第二个参数为提供该命令的yum 软件包名称
check_yum_command() {
- output_msg "命令检查:$1"
- hash $1 >/dev/null 2>&1
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` check command $1 ">>${install_log_path}${install_log_name} && return 0
- else
- yum -y install $2 >/dev/null 2>&1
- # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
- fi
+ output_msg "命令检查:$1"
+ hash $1 > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` check command $1 " >> ${install_log_path}${install_log_name} && return 0
+ else
+ yum -y install $2 > /dev/null 2>&1
+ # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
+ fi
}
# 判断目录是否存在,传入目录绝对路径,可以传入多个目录
check_dir() {
- output_msg "目录检查"
- for dirname in $*;do
- [ -d $dirname ] || mkdir -p $dirname >/dev/null 2>&1
- echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
- done
+ output_msg "目录检查"
+ for dirname in $*; do
+ [ -d $dirname ] || mkdir -p $dirname > /dev/null 2>&1
+ echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
+ done
}
# 下载文件并解压至安装目录,传入url链接地址
download_file() {
- output_msg "下载源码包"
- mkdir -p $download_path
- for file in $*;do
- wget $file -c -P $download_path &> /dev/null
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` $file download success!">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%s` $file download fail!">>${install_log_path}${install_log_name} && exit 1
- fi
- done
+ output_msg "下载源码包"
+ mkdir -p $download_path
+ for file in $*; do
+ wget $file -c -P $download_path &> /dev/null
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` $file download success!" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%s` $file download fail!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ done
}
# 解压文件,可以传入多个压缩文件绝对路径,用空格隔开,解压至安装目录
extract_file() {
- output_msg "解压源码"
- for file in $*;do
- if [ "${file##*.}" == "gz" ];then
- tar -zxf $file -C $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path">>${install_log_path}${install_log_name}
- elif [ "${file##*.}" == "zip" ];then
- unzip -q $file -d $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%S` $file type error, extrac fail!">>${install_log_path}${install_log_name} && exit 1
- fi
- done
+ output_msg "解压源码"
+ for file in $*; do
+ if [ "${file##*.}" == "gz" ]; then
+ tar -zxf $file -C $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path" >> ${install_log_path}${install_log_name}
+ elif [ "${file##*.}" == "zip" ]; then
+ unzip -q $file -d $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%S` $file type error, extrac fail!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ done
}
# 配置环境变量,第一个参数为添加环境变量的绝对路径
config_env() {
- output_msg "环境变量配置"
- echo "export PATH=\$PATH:$1" >${env_file}
- source ${env_file} && echo "`date +%F' '%H:%M:%S` 软件安装完成!">> ${install_log_path}${install_log_name}
+ output_msg "环境变量配置"
+ echo "export PATH=\$PATH:$1" > ${env_file}
+ source ${env_file} && echo "`date +%F' '%H:%M:%S` 软件安装完成!" >> ${install_log_path}${install_log_name}
}
# 添加配置文件
add_config() {
-cat> $1 < $1 << EOF
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.url: "http://127.0.0.1:9200"
@@ -116,18 +117,18 @@ EOF
}
main() {
-check_dir $install_log_path $install_path
-check_yum_command wget wget
-download_file $URL
-
-software_name=$(echo $URL|awk -F'/' '{print $NF}'|awk -F'.tar.gz' '{print $1}')
-for filename in `ls $download_path`;do
- extract_file ${download_path}$filename
-done
-rm -fr ${download_path}
-ln -s ${install_path}$software_name ${install_path}kibana
-add_config ${software_config_file}
-config_env ${install_path}kibana/bin
+ check_dir $install_log_path $install_path
+ check_yum_command wget wget
+ download_file $URL
+
+ software_name=$(echo $URL | awk -F'/' '{print $NF}' | awk -F'.tar.gz' '{print $1}')
+ for filename in `ls $download_path`; do
+ extract_file ${download_path}$filename
+ done
+ rm -fr ${download_path}
+ ln -s ${install_path}$software_name ${install_path}kibana
+ add_config ${software_config_file}
+ config_env ${install_path}kibana/bin
}
main
diff --git a/codes/linux/soft/elk/install_logstash.sh b/codes/linux/soft/elk/install_logstash.sh
index 673e52de..92546afe 100644
--- a/codes/linux/soft/elk/install_logstash.sh
+++ b/codes/linux/soft/elk/install_logstash.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# auth:kaliarch
# version:v1.0
# func:logstash 5.4/6.1/6.3 安装
@@ -26,89 +27,89 @@ echo "3: Install logstash-6.3"
echo "4: EXIT"
# 选择安装软件版本
read -p "Please input your choice:" softversion
-if [ "${softversion}" == "1" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/logstash/logstash-5.4.1.tar.gz"
-elif [ "${softversion}" == "2" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/logstash/logstash-6.1.3.tar.gz"
-elif [ "${softversion}" == "3" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/logstash/logstash-6.3.2.tar.gz"
-elif [ "${softversion}" == "4" ];then
- echo "you choce channel!"
- exit 1;
+if [ "${softversion}" == "1" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/logstash/logstash-5.4.1.tar.gz"
+elif [ "${softversion}" == "2" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/logstash/logstash-6.1.3.tar.gz"
+elif [ "${softversion}" == "3" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/logstash/logstash-6.3.2.tar.gz"
+elif [ "${softversion}" == "4" ]; then
+ echo "you choce channel!"
+ exit 1;
else
- echo "input Error! Place input{1|2|3|4}"
- exit 0;
+ echo "input Error! Place input{1|2|3|4}"
+ exit 0;
fi
# 传入内容,格式化内容输出,可以传入多个参数,用空格隔开
output_msg() {
- for msg in $*;do
- action $msg /bin/true
- done
+ for msg in $*; do
+ action $msg /bin/true
+ done
}
# 判断命令是否存在,第一个参数 $1 为判断的命令,第二个参数为提供该命令的yum 软件包名称
check_yum_command() {
- output_msg "命令检查:$1"
- hash $1 >/dev/null 2>&1
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` check command $1 ">>${install_log_path}${install_log_name} && return 0
- else
- yum -y install $2 >/dev/null 2>&1
- # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
- fi
+ output_msg "命令检查:$1"
+ hash $1 > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` check command $1 " >> ${install_log_path}${install_log_name} && return 0
+ else
+ yum -y install $2 > /dev/null 2>&1
+ # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
+ fi
}
# 判断目录是否存在,传入目录绝对路径,可以传入多个目录
check_dir() {
- output_msg "目录检查"
- for dirname in $*;do
- [ -d $dirname ] || mkdir -p $dirname >/dev/null 2>&1
- echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
- done
+ output_msg "目录检查"
+ for dirname in $*; do
+ [ -d $dirname ] || mkdir -p $dirname > /dev/null 2>&1
+ echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
+ done
}
# 下载文件并解压至安装目录,传入url链接地址
download_file() {
- output_msg "下载源码包"
- mkdir -p $download_path
- for file in $*;do
- wget $file -c -P $download_path &> /dev/null
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` $file download success!">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%s` $file download fail!">>${install_log_path}${install_log_name} && exit 1
- fi
- done
+ output_msg "下载源码包"
+ mkdir -p $download_path
+ for file in $*; do
+ wget $file -c -P $download_path &> /dev/null
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` $file download success!" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%s` $file download fail!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ done
}
# 解压文件,可以传入多个压缩文件绝对路径,用空格隔开,解压至安装目录
extract_file() {
- output_msg "解压源码"
- for file in $*;do
- if [ "${file##*.}" == "gz" ];then
- tar -zxf $file -C $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path">>${install_log_path}${install_log_name}
- elif [ "${file##*.}" == "zip" ];then
- unzip -q $file -d $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%S` $file type error, extrac fail!">>${install_log_path}${install_log_name} && exit 1
- fi
- done
+ output_msg "解压源码"
+ for file in $*; do
+ if [ "${file##*.}" == "gz" ]; then
+ tar -zxf $file -C $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path" >> ${install_log_path}${install_log_name}
+ elif [ "${file##*.}" == "zip" ]; then
+ unzip -q $file -d $install_path && echo "`date +%F' '%H:%M:%S` $file extrac success!,path is $install_path" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%S` $file type error, extrac fail!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ done
}
# 配置环境变量,第一个参数为添加环境变量的绝对路径
config_env() {
- output_msg "环境变量配置"
- echo "export PATH=\$PATH:$1" >${env_file}
- source ${env_file} && echo "`date +%F' '%H:%M:%S` 软件安装完成!">> ${install_log_path}${install_log_name}
+ output_msg "环境变量配置"
+ echo "export PATH=\$PATH:$1" > ${env_file}
+ source ${env_file} && echo "`date +%F' '%H:%M:%S` 软件安装完成!" >> ${install_log_path}${install_log_name}
}
# 添加配置文件
add_config() {
-cat> $1 < $1 << EOF
input {
beats {
port => "5044"
@@ -124,18 +125,18 @@ EOF
}
main() {
-check_dir $install_log_path $install_path
-check_yum_command wget wget
-download_file $URL
-
-software_name=$(echo $URL|awk -F'/' '{print $NF}'|awk -F'.tar.gz' '{print $1}')
-for filename in `ls $download_path`;do
- extract_file ${download_path}$filename
-done
-rm -fr ${download_path}
-ln -s $install_path$software_name ${install_path}logstash
-add_config ${software_config_file}
-config_env ${install_path}logstash/bin
+ check_dir $install_log_path $install_path
+ check_yum_command wget wget
+ download_file $URL
+
+ software_name=$(echo $URL | awk -F'/' '{print $NF}' | awk -F'.tar.gz' '{print $1}')
+ for filename in `ls $download_path`; do
+ extract_file ${download_path}$filename
+ done
+ rm -fr ${download_path}
+ ln -s $install_path$software_name ${install_path}logstash
+ add_config ${software_config_file}
+ config_env ${install_path}logstash/bin
}
main
diff --git a/codes/linux/soft/fastdfs-install.sh b/codes/linux/soft/fastdfs-install.sh
index 4ac701bd..95cfb009 100644
--- a/codes/linux/soft/fastdfs-install.sh
+++ b/codes/linux/soft/fastdfs-install.sh
@@ -28,26 +28,32 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install fastdfs begin.${RESET}\n"
-command -v yum >/dev/null 2>&1 || { printf "${RED}Require yum but it's not installed.${RESET}\n"; exit 1; }
-command -v git >/dev/null 2>&1 || { printf "${RED}Require git but it's not installed.${RESET}\n"; exit 1; }
-
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- printf "${PURPLE}[Hint]\n"
- printf "\t sh fastdfs-install.sh [path]\n"
- printf "\t Example: sh fastdfs-install.sh /opt/fastdfs\n"
- printf "${RESET}\n"
+command -v yum > /dev/null 2>&1 || {
+ printf "${RED}Require yum but it's not installed.${RESET}\n";
+ exit 1;
+}
+command -v git > /dev/null 2>&1 || {
+ printf "${RED}Require git but it's not installed.${RESET}\n";
+ exit 1;
+}
+
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t sh fastdfs-install.sh [path]\n"
+ printf "\t Example: sh fastdfs-install.sh /opt/fastdfs\n"
+ printf "${RESET}\n"
fi
path=/opt/fdfs
if [[ -n $1 ]]; then
- path=$1
+ path=$1
fi
nginx_version=1.16.0
nginx_path=/opt/nginx
printf "${GREEN}>>>>>>>> install required libs.${RESET}\n\n"
-yum install git gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl-devel wget vim -y
+yum install -y git gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl-devel wget vim unzip
# download and decompression
mkdir -p ${path}
@@ -55,8 +61,8 @@ path=/opt/fdfs
mkdir -p ${path}/libfastcommon
curl -o ${path}/libfastcommon.zip http://dunwu.test.upcdn.net/soft/fdfs/libfastcommon.zip
if [[ ! -f ${path}/libfastcommon.zip ]]; then
- printf "${RED}[Error]install libfastcommon failed,exit. ${RESET}\n"
- exit 1
+ printf "${RED}[Error]install libfastcommon failed,exit. ${RESET}\n"
+ exit 1
fi
unzip -o ${path}/libfastcommon.zip -d ${path}
@@ -69,7 +75,7 @@ printf "${GREEN}>>>>>>>>> install fastdfs${RESET}"
mkdir -p ${path}/fastdfs
curl -o ${path}/fastdfs.zip http://dunwu.test.upcdn.net/soft/fdfs/fastdfs.zip
if [[ ! -f ${path}/fastdfs.zip ]]; then
- printf "${RED}>>>>>>>>> install fastdfs failed,exit. ${RESET}\n"
+ printf "${RED}>>>>>>>>> install fastdfs failed,exit. ${RESET}\n"
fi
unzip -o ${path}/fastdfs.zip -d ${path}
cd ${path}/fastdfs
@@ -80,7 +86,7 @@ printf "${GREEN}>>>>>>>>> install fastdfs-nginx-module${RESET}\n"
mkdir -p ${path}/fastdfs-nginx-module
curl -o ${path}/fastdfs-nginx-module.zip http://dunwu.test.upcdn.net/soft/fdfs/fastdfs-nginx-module.zip
if [[ ! -f ${path}/fastdfs-nginx-module.zip ]]; then
- printf "${RED}>>>>>>>>> install fastdfs-nginx-module failed,exit. ${RESET}\n"
+ printf "${RED}>>>>>>>>> install fastdfs-nginx-module failed,exit. ${RESET}\n"
fi
unzip -o ${path}/fastdfs-nginx-module.zip -d ${path}
@@ -95,6 +101,7 @@ make && make install
printf "${GREEN}>>>>>>>>> fastdfs 配置文件准备${RESET}\n"
# 配置修改参考:https://github.com/happyfish100/fastdfs/wiki
+mkdir -p /etc/fdfs
cp ${path}/fastdfs/conf/http.conf /etc/fdfs/ #供nginx访问使用
cp ${path}/fastdfs/conf/mime.types /etc/fdfs/ #供nginx访问使用
cp ${path}/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs
diff --git a/codes/linux/soft/gitlab-install.sh b/codes/linux/soft/gitlab-install.sh
index f06b5e65..971a3a48 100644
--- a/codes/linux/soft/gitlab-install.sh
+++ b/codes/linux/soft/gitlab-install.sh
@@ -1,25 +1,110 @@
#!/usr/bin/env bash
-###################################################################################
-# 安装 Gitlab 脚本
+# -----------------------------------------------------------------------------------------------------
+# Gitlab 安装脚本
# 仅适用于 CentOS7 发行版本
+# 官方安裝參考:https://about.gitlab.com/install/#centos-7
# @author: Zhang Peng
-###################################################################################
+# -----------------------------------------------------------------------------------------------------
-echo -e "\n>>>>>>>>> install gitlab"
+# ------------------------------------------------------------------------------ env
-echo -e "\n>>>>>>>>> 安装和配置必要依赖"
-sudo yum install -y curl policycoreutils-python openssh-server
-sudo systemctl enable sshd
-sudo systemctl start sshd
-sudo firewall-cmd --permanent --add-service=http
-sudo systemctl reload firewalld
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+# ------------------------------------------------------------------------------ functions
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
-echo -e "\n>>>>>>>>> 安装和配置邮件服务"
-sudo yum install postfix
-sudo systemctl enable postfix
-sudo systemctl start postfix
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
-echo -e "\n>>>>>>>>> 通过 yum 安装 gitlab"
-curl -o- https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash
-sudo EXTERNAL_URL="http://gitlab.example.com" yum install -y gitlab-ce
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ printInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ printError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
+
+# ------------------------------------------------------------------------------ main
+
+# 官方安裝參考:https://about.gitlab.com/install/#centos-7
+printInfo ">>>> install gitlab on Centos7"
+printInfo ">>>> Install and configure the necessary dependencies"
+yum install -y curl policycoreutils-python openssh-server
+systemctl enable sshd
+systemctl start sshd
+printInfo ">>>> open http, https and ssh access in the system firewall"
+sudo firewall-cmd --permanent --add-service=http
+sudo firewall-cmd --permanent --add-service=https
+sudo systemctl reload firewalld
+printInfo ">>>> install postfix"
+yum install postfix
+systemctl enable postfix
+systemctl start postfix
+printInfo ">>>> Add the GitLab package repository and install the package"
+curl -o- https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | bash
+EXTERNAL_URL="http://gitlab.transwarp.io" yum install -y gitlab-ce
diff --git a/codes/linux/soft/gitlab/gitlab-backup.sh b/codes/linux/soft/gitlab/gitlab-backup.sh
new file mode 100644
index 00000000..0a341510
--- /dev/null
+++ b/codes/linux/soft/gitlab/gitlab-backup.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# Gitlab 操作脚本
+# 支持操作:
+# 备份 Gitlab
+# 恢复 Gitlab
+# @author: Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+
+# ------------------------------------------------------------------------------ env
+
+# Gilab 操作的环境变量,使用方法:
+# 可以在执行本脚本之前,export 以下环境变量,否则将按照默认配置执行
+
+# Gitlab 备份文件最大数量(默认为 7 天)
+export ENV_BACKUP_MAX_NUM=7
+# 备份路径
+export ENV_GITLAB_BACKUP_DIR="/var/opt/gitlab/backups"
+# 备份日志路径
+export ENV_LOG_PATH="${ENV_GITLAB_BACKUP_DIR}/gitlab-backup.log"
+
+ENV_REMOTE_USER=root
+ENV_REMOTE_HOST=172.22.6.42
+
+# ------------------------------------------------------------------------------ load libs
+
+GIT_SCRIPTS_DIR=$(cd `dirname $0`; pwd)
+if [[ ! -x ${GIT_SCRIPTS_DIR}/gitlab.sh ]]; then
+ echo "${GIT_SCRIPTS_DIR}/gitlab.sh not exists!"
+ exit 1
+fi
+source ${GIT_SCRIPTS_DIR}/gitlab.sh
+
+# ------------------------------------------------------------------------------ functions
+
+backupGitlab
+if [[ "$?" != ${ENV_SUCCEED} ]]; then
+ printError "退出"
+ exit ${ENV_FAILED}
+fi
+
+#将备份文件传输到gitlab备份服务器
+BACKUP_FILE=$(find "${ENV_GITLAB_BACKUP_DIR}" -type f -name "*gitlab_backup.tar" | xargs ls -t | head -1)
+scp ${BACKUP_FILE} ${ENV_REMOTE_USER}@${ENV_REMOTE_HOST}:${ENV_GITLAB_BACKUP_DIR}
diff --git a/codes/linux/soft/gitlab/gitlab.sh b/codes/linux/soft/gitlab/gitlab.sh
new file mode 100644
index 00000000..a2ba3c66
--- /dev/null
+++ b/codes/linux/soft/gitlab/gitlab.sh
@@ -0,0 +1,191 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# Gitlab 操作脚本
+# 支持操作:
+# 备份 Gitlab
+# 恢复 Gitlab
+# @author: Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env
+
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+# ------------------------------------------------------------------------------ functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ printInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ printError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
+
+# ------------------------------------------------------------------------------ env
+
+# Gilab 操作的环境变量,使用方法:
+# 可以在执行本脚本之前,export 以下环境变量,否则将按照默认配置执行
+
+# Gitlab 备份文件最大数量(默认为 7 天)
+ENV_BACKUP_MAX_NUM=${ENV_BACKUP_MAX_NUM:-2}
+# 备份路径
+ENV_GITLAB_BACKUP_DIR="${ENV_GITLAB_BACKUP_DIR:-/var/opt/gitlab/backups}"
+# 备份日志路径
+ENV_LOG_PATH="${ENV_GITLAB_BACKUP_DIR}/gitlab-backup.log"
+
+magentaOutput "------------------------------------------------------------------------------"
+magentaOutput "Gitlab 脚本操作环境变量:"
+magentaOutput "ENV_BACKUP_MAX_NUM:${ENV_BACKUP_MAX_NUM}"
+magentaOutput "ENV_GITLAB_BACKUP_DIR:${ENV_GITLAB_BACKUP_DIR}"
+magentaOutput "ENV_LOG_PATH:${ENV_LOG_PATH}"
+magentaOutput "------------------------------------------------------------------------------"
+
+
+# ------------------------------------------------------------------------------ functions
+
+# 安装 Gitlab
+installGitlab() {
+ # 官方安裝參考:https://about.gitlab.com/install/#centos-7
+ printInfo ">>>> install gitlab on Centos7"
+ printInfo ">>>> Install and configure the necessary dependencies"
+ yum install -y curl policycoreutils-python openssh-server
+ systemctl enable sshd
+ systemctl start sshd
+ printInfo ">>>> open http, https and ssh access in the system firewall"
+ sudo firewall-cmd --permanent --add-service=http
+ sudo firewall-cmd --permanent --add-service=https
+ sudo systemctl reload firewalld
+ printInfo ">>>> install postfix"
+ yum install postfix
+ systemctl enable postfix
+ systemctl start postfix
+ printInfo ">>>> Add the GitLab package repository and install the package"
+ curl -o- https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | bash
+ EXTERNAL_URL="http://gitlab.transwarp.io" yum install -y gitlab-ce
+}
+
+# 备份 Gitlab
+backupGitlab() {
+
+ #时间戳
+ local beginTime=$(date +'%Y-%m-%d %H:%M:%S')
+
+ #备份所有数据库
+ printInfo ">>>> 备份 Gitlab 开始"
+ gitlab-rake gitlab:backup:create >> ${ENV_LOG_PATH};
+
+ #检查备份结果是否成功
+ if [[ "$?" != ${ENV_SUCCEED} ]]; then
+ printError "<<<< 备份 Gitlab 失败"
+ return ${ENV_FAILED}
+ fi
+
+ # 压缩备份sql文件,删除旧的备份文件
+ cd "${ENV_GITLAB_BACKUP_DIR}"
+
+ #只保存期限内的备份文件,其余删除
+ find "${ENV_GITLAB_BACKUP_DIR} -name *_gitlab_backup.tar -type f -mtime +${ENV_BACKUP_MAX_NUM} -exec rm -rf {} \;" > /dev/null 2>&1
+
+ local endTime=$(date +'%Y-%m-%d %H:%M:%S')
+ local beginSeconds=$(date --date="${beginTime}" +%s)
+ local endSeconds=$(date --date="${endTime}" +%s)
+ printInfo "本次备份执行时间:$((endSeconds-beginSeconds)) s"
+ printInfo "<<<< 备份 Gitlab 成功\n"
+ return ${ENV_SUCCEED}
+}
+
+# 恢复 Mysql
+recoveryGitlab() {
+
+ local version=$1
+ if [[ !version ]]; then
+ printError "<<<< 未指定恢复版本"
+ return ${ENV_FAILED}
+ fi
+
+ #创建备份目录及日志文件
+ mkdir -p ${ENV_GITLAB_BACKUP_DIR}
+ if [[ ! -f ${ENV_LOG_PATH} ]]; then
+ touch ${ENV_LOG_PATH}
+ fi
+
+ printInfo ">>>> 恢复 Gitlab 开始"
+
+ gitlab-ctl stop unicorn
+ gitlab-ctl stop sidekiq
+
+ gitlab-rake gitlab:backup:restore BACKUP=${version}
+ if [[ "$?" != 0 ]]; then
+ printError "<<<< 恢复 Gitlab 失败"
+ return ${ENV_FAILED}
+ fi
+
+ printInfo "<<<< 恢复 Gitlab 成功\n"
+ return ${ENV_SUCCEED}
+}
diff --git a/codes/linux/soft/install_grafana.sh b/codes/linux/soft/install_grafana.sh
index 36ddc399..4364429f 100644
--- a/codes/linux/soft/install_grafana.sh
+++ b/codes/linux/soft/install_grafana.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# auth:kaliarch
# version:v1.0
# func:grafana 5.1.0/5.1.5/5.2.2 安装
@@ -25,85 +26,85 @@ echo "3: Install grafana 5.2.2"
echo "4: EXIT"
# 选择安装软件版本
read -p "Please input your choice:" softversion
-if [ "${softversion}" == "1" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/grafana/grafana-5.1.0-1.x86_64.rpm"
-elif [ "${softversion}" == "2" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/grafana/grafana-5.1.5-1.x86_64.rpm"
-elif [ "${softversion}" == "3" ];then
- URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/grafana/grafana-5.2.2-1.x86_64.rpm"
-elif [ "${softversion}" == "4" ];then
- echo "you choce channel!"
- exit 1;
+if [ "${softversion}" == "1" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/grafana/grafana-5.1.0-1.x86_64.rpm"
+elif [ "${softversion}" == "2" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/grafana/grafana-5.1.5-1.x86_64.rpm"
+elif [ "${softversion}" == "3" ]; then
+ URL="https://anchnet-script.oss-cn-shanghai.aliyuncs.com/grafana/grafana-5.2.2-1.x86_64.rpm"
+elif [ "${softversion}" == "4" ]; then
+ echo "you choce channel!"
+ exit 1;
else
- echo "input Error! Place input{1|2|3|4}"
- exit 0;
+ echo "input Error! Place input{1|2|3|4}"
+ exit 0;
fi
# 传入内容,格式化内容输出,可以传入多个参数,用空格隔开
output_msg() {
- for msg in $*;do
- action $msg /bin/true
- done
+ for msg in $*; do
+ action $msg /bin/true
+ done
}
# 判断命令是否存在,第一个参数 $1 为判断的命令,第二个参数为提供该命令的yum 软件包名称
check_yum_command() {
- output_msg "命令检查:$1"
- hash $1 >/dev/null 2>&1
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` check command $1 ">>${install_log_path}${install_log_name} && return 0
- else
- yum -y install $2 >/dev/null 2>&1
- # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
- fi
+ output_msg "命令检查:$1"
+ hash $1 > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` check command $1 " >> ${install_log_path}${install_log_name} && return 0
+ else
+ yum -y install $2 > /dev/null 2>&1
+ # hash $Command || { echo "`date +%F' '%H:%M:%S` $2 is installed fail">>${install_log_path}${install_log_name} ; exit 1 }
+ fi
}
# 判断目录是否存在,传入目录绝对路径,可以传入多个目录
check_dir() {
- output_msg "目录检查"
- for dirname in $*;do
- [ -d $dirname ] || mkdir -p $dirname >/dev/null 2>&1
- echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
- done
+ output_msg "目录检查"
+ for dirname in $*; do
+ [ -d $dirname ] || mkdir -p $dirname > /dev/null 2>&1
+ echo "`date +%F' '%H:%M:%S` $dirname check success!" >> ${install_log_path}${install_log_name}
+ done
}
# 下载文件并解压至安装目录,传入url链接地址
download_file() {
- output_msg "下载源码包"
- mkdir -p $download_path
- for file in $*;do
- wget $file -c -P $download_path &> /dev/null
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` $file download success!">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%s` $file download fail!">>${install_log_path}${install_log_name} && exit 1
- fi
- done
+ output_msg "下载源码包"
+ mkdir -p $download_path
+ for file in $*; do
+ wget $file -c -P $download_path &> /dev/null
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` $file download success!" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%s` $file download fail!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
+ done
}
# 安装grafana插件,传入安装的插件的名称
install_grafana_plugins() {
- output_msg "grafana插件安装"
- check_yum_command grafana-cli
- grafana-cli plugins install $* >/dev/null
- if [ $? -eq 0 ];then
- echo "`date +%F' '%H:%M:%S` grafana plugins $* install success!">>${install_log_path}${install_log_name}
- else
- echo "`date +%F' '%H:%M:%s` grafana plugins $* install success!">>${install_log_path}${install_log_name} && exit 1
- fi
+ output_msg "grafana插件安装"
+ check_yum_command grafana-cli
+ grafana-cli plugins install $* > /dev/null
+ if [ $? -eq 0 ]; then
+ echo "`date +%F' '%H:%M:%S` grafana plugins $* install success!" >> ${install_log_path}${install_log_name}
+ else
+ echo "`date +%F' '%H:%M:%s` grafana plugins $* install success!" >> ${install_log_path}${install_log_name} && exit 1
+ fi
}
main() {
-check_dir $install_log_path $install_path
-check_yum_command wget wget
-download_file $URL
-for filename in `ls $download_path`;do
- yum -y install $download_path$filename >/dev/null 2>&1
-done
-install_grafana_plugins alexanderzobnin-zabbix-app
+ check_dir $install_log_path $install_path
+ check_yum_command wget wget
+ download_file $URL
+ for filename in `ls $download_path`; do
+ yum -y install $download_path$filename > /dev/null 2>&1
+ done
+ install_grafana_plugins alexanderzobnin-zabbix-app
}
main
diff --git a/codes/linux/soft/jdk8-install.sh b/codes/linux/soft/jdk8-install.sh
index 24618255..b08733e7 100644
--- a/codes/linux/soft/jdk8-install.sh
+++ b/codes/linux/soft/jdk8-install.sh
@@ -27,7 +27,10 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install jdk8 begin.${RESET}\n"
-command -v yum >/dev/null 2>&1 || { printf "${RED}Require yum but it's not installed.${RESET}\n"; exit 1; }
+command -v yum > /dev/null 2>&1 || {
+ printf "${RED}Require yum but it's not installed.${RESET}\n";
+ exit 1;
+}
yum -y install java-1.8.0-openjdk-devel.x86_64
java -version
diff --git a/codes/linux/soft/kafka-install.sh b/codes/linux/soft/kafka-install.sh
index d7282d3c..a8cced56 100644
--- a/codes/linux/soft/kafka-install.sh
+++ b/codes/linux/soft/kafka-install.sh
@@ -26,23 +26,26 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install kafka begin.${RESET}\n"
-command -v java >/dev/null 2>&1 || { printf "${RED}Require java but it's not installed.${RESET}\n"; exit 1; }
-
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- printf "${PURPLE}[Hint]\n"
- printf "\t sh kafka-install.sh [version] [path]\n"
- printf "\t Example: sh kafka-install.sh 2.2.0 /opt/kafka\n"
- printf "${RESET}\n"
+command -v java > /dev/null 2>&1 || {
+ printf "${RED}Require java but it's not installed.${RESET}\n";
+ exit 1;
+}
+
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t sh kafka-install.sh [version] [path]\n"
+ printf "\t Example: sh kafka-install.sh 2.2.0 /opt/kafka\n"
+ printf "${RESET}\n"
fi
version=2.2.0
if [[ -n $1 ]]; then
- version=$1
+ version=$1
fi
path=/opt/kafka
if [[ -n $2 ]]; then
- path=$2
+ path=$2
fi
# install info
diff --git a/codes/linux/soft/lib/docker.sh b/codes/linux/soft/lib/docker.sh
new file mode 100644
index 00000000..7ef09f3c
--- /dev/null
+++ b/codes/linux/soft/lib/docker.sh
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+
+LINUX_SCRIPTS_LIB_DIR=`dirname ${BASH_SOURCE[0]}`
+source ${LINUX_SCRIPTS_LIB_DIR}/utils.sh
+
+dockerBuild() {
+ if [[ ! $1 ]] || [[ ! $2 ]] || [[ ! $3 ]]; then
+ logError "you must input following params in order:"
+ echo -e "${ENV_COLOR_B_RED}"
+ echo " (1) source"
+ echo " (2) repository"
+ echo " (3) tag"
+ echo -e "\nEg. dockerBuild /home/workspace tdh60dev01:5000/fide/fide-processor fide-0.0.6-SNAPSHOT"
+ echo -e "${ENV_COLOR_RESET}"
+ return ${ENV_FAILED}
+ fi
+
+ local source=$1
+ local repository=$2
+ local tag=$3
+
+ dockerCheck ${source}
+ if [[ "${ENV_SUCCEED}" != "$?" ]]; then
+ return ${ENV_FAILED}
+ fi
+
+ cd ${source}
+ callAndLog docker build -t ${repository}:${tag} .
+ if [[ "${ENV_SUCCEED}" != "$?" ]]; then
+ logError "docker build -t ${repository}:${tag} failed"
+ return ${ENV_FAILED}
+ fi
+
+ cd -
+}
+
+dockerPush() {
+ if [[ ! $1 ]] || [[ ! $2 ]]; then
+ logError "you must input following params in order:"
+ echo -e "${ENV_COLOR_B_RED}"
+ echo " (1) repository"
+ echo " (2) tag"
+ echo -e "\nEg. dockerBuild tdh60dev01:5000/fide/fide-processor fide-0.0.6-SNAPSHOT"
+ echo -e "${ENV_COLOR_RESET}"
+ return ${ENV_FAILED}
+ fi
+
+ local repository=$1
+ local tag=$2
+
+ local dockerHashId=$(docker image ls | grep ${repository} | grep ${tag} | awk '{print $3}')
+ if [[ ! ${dockerHashId} ]]; then
+ logInfo "try to delete existed image: ${repository}:${tag}"
+ callAndLog docker rmi ${dockerHashId}
+ fi
+
+ logInfo "try to push new image: ${repository}:${tag}"
+ callAndLog docker push ${repository}:${tag}
+}
+
+# check Dockerfile
+# @param $1: project path
+dockerCheck() {
+ local source=$1
+ if [[ -d "${source}" ]]; then
+ cd ${source}
+ if [[ -f "${source}/Dockerfile" ]]; then
+ return ${ENV_YES}
+ else
+ logError "Dockerfile is not exists"
+ return ${ENV_NO}
+ fi
+ cd -
+ return ${ENV_YES}
+ else
+ logError "${source} is not valid docker project"
+ return ${ENV_NO}
+ fi
+}
diff --git a/codes/linux/soft/lib/file.sh b/codes/linux/soft/lib/file.sh
new file mode 100644
index 00000000..465f1aed
--- /dev/null
+++ b/codes/linux/soft/lib/file.sh
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+
+# 装载其它库
+ROOT=`dirname ${BASH_SOURCE[0]}`
+source ${ROOT}/utils.sh
+
+# ------------------------------------------------------------------------------ 文件操作函数
+
+# 文件是否存在
+isFileExists() {
+ if [[ -e $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+isFile() {
+ if [[ -f $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+isDirectory() {
+ if [[ -d $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+isFileReadable() {
+ if [[ -r $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+isFileWritable() {
+ if [[ -w $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+isFileExecutable() {
+ if [[ -x $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+# 检查文件夹是否存在,不存在则创建
+createFolderIfNotExist() {
+ if [ ! -d "$1" ]; then
+ mkdir -p "$1"
+ fi
+}
+
+# 重建目录,如果目录已存在,则删除后重建;如果不存在,直接新建
+recreateDir() {
+ if [[ ! $1 ]]; then
+ printf "${C_B_RED}<<<< Please input dir path.${C_RESET}\n"
+ return ${FAILED}
+ fi
+
+ rm -rf $1
+ mkdir -p $1
+
+ isDirectory $1
+ if [[ "$?" != "${SUCCEED}" ]]; then
+ printf "${C_B_RED}<<<< create $1 failed.${C_RESET}\n"
+ return ${FAILED}
+ fi
+
+ return ${SUCCEED}
+}
diff --git a/codes/linux/soft/lib/git.sh b/codes/linux/soft/lib/git.sh
new file mode 100644
index 00000000..c729cc7e
--- /dev/null
+++ b/codes/linux/soft/lib/git.sh
@@ -0,0 +1,219 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# Shell Utils
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env
+
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Underline Color
+export ENV_COLOR_U_BLACK="\033[4;30m"
+export ENV_COLOR_U_RED="\033[4;31m"
+export ENV_COLOR_U_GREEN="\033[4;32m"
+export ENV_COLOR_U_YELLOW="\033[4;33m"
+export ENV_COLOR_U_BLUE="\033[4;34m"
+export ENV_COLOR_U_MAGENTA="\033[4;35m"
+export ENV_COLOR_U_CYAN="\033[4;36m"
+export ENV_COLOR_U_WHITE="\033[4;37m"
+# Background Color
+export ENV_COLOR_BG_BLACK="\033[40m"
+export ENV_COLOR_BG_RED="\033[41m"
+export ENV_COLOR_BG_GREEN="\033[42m"
+export ENV_COLOR_BG_YELLOW="\033[43m"
+export ENV_COLOR_BG_BLUE="\033[44m"
+export ENV_COLOR_BG_MAGENTA="\033[45m"
+export ENV_COLOR_BG_CYAN="\033[46m"
+export ENV_COLOR_BG_WHITE="\033[47m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+
+# ------------------------------------------------------------------------------ util functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+# 日志路径
+LOG_PATH=${ENV_LOG_PATH:-/var/log/shell.log}
+# 日志目录
+LOG_DIR=${LOG_PATH%/*}
+
+createLogFileIfNotExists() {
+ if [[ ! -x "${LOG_PATH}" ]]; then
+ mkdir -p "${LOG_DIR}"
+ touch "${LOG_PATH}"
+ fi
+}
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
+
+logInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [INFO] [$0] $@" >> "${LOG_PATH}"
+}
+logWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [WARN] [$0] $@" >> "${LOG_PATH}"
+}
+logError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [ERROR] [$0] $@" >> "${LOG_PATH}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ logInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ logError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
+
+# ------------------------------------------------------------------------------ git functions
+
+getGitLocalBranch() {
+ export GIT_LOCAL_BRANCH=$(git symbolic-ref -q --short HEAD)
+}
+
+getGitOriginBranch() {
+ export GIT_ORIGIN_BRANCH=$(git rev-parse --abbrev-ref --symbolic-full-name "@{u}")
+}
+
+# check specified path is git project or not
+IS_GIT=false
+checkGit() {
+ local source=$1
+ if [[ -d "${source}" ]]; then
+ cd ${source}
+ # (1) delete gitstatus.tmp
+ if [[ -f "gitstatus.tmp" ]]; then
+ rm -rf gitstatus.tmp
+ fi
+
+ # (2) check git status
+ git status &> gitstatus.tmp
+ local gitStatus=false
+ grep -iwq 'not a git repository' gitstatus.tmp && gitStatus=false || gitStatus=true
+ rm -rf gitstatus.tmp
+ if [[ ${gitStatus} == true ]]; then
+ export IS_GIT=true
+ return
+ fi
+ fi
+
+ logWarn "${source} is not exists."
+ export IS_GIT=false
+}
+
+# execute git clone or fetch
+# params: Git repository, git group, git project, git branch, local path
+cloneOrPullGit() {
+
+ local repository=$1
+ local group=$2
+ local project=$3
+ local branch=$4
+ local root=$5
+
+ if [[ ! ${repository} || ! ${group} || ! ${project} || ! ${branch} || ! ${root} ]]; then
+ logError "Please input root, group, project, branch."
+ return ${ENV_FAILED}
+ fi
+
+ if [[ ! -d "${root}" ]]; then
+ logError "${root} is not directory."
+ return ${ENV_FAILED}
+ fi
+
+ local source=${root}/${group}/${project}
+ logInfo "project directory is ${source}."
+ logInfo "git url is ${repository}:${group}/${project}.git."
+
+ checkGit ${source}
+ if [[ "${IS_GIT}" == "true" ]]; then
+ cd ${source} || return ${ENV_FAILED}
+
+ git checkout ${branch}
+ logInfo "git checkout ${branch} succeed."
+
+ git fetch --all
+ git reset --hard ${GIT_ORIGIN_BRANCH}
+ logInfo "git reset --hard ${GIT_ORIGIN_BRANCH} succeed."
+
+ git pull
+ logInfo "git pull succeed."
+ else
+ git clone "${repository}:${group}/${project}.git" ${source}
+ logInfo "git clone ${project} succeed."
+
+ cd ${source} || return ${ENV_FAILED}
+
+ git checkout ${branch}
+ logInfo "git checkout ${branch} succeed."
+ fi
+
+ logInfo "Clone or pull git project [$2/$3:$4] succeed."
+ cd ${SOURCE_DIR}
+ return ${ENV_SUCCEED}
+}
diff --git a/codes/linux/soft/lib/java.sh b/codes/linux/soft/lib/java.sh
new file mode 100644
index 00000000..84276bcc
--- /dev/null
+++ b/codes/linux/soft/lib/java.sh
@@ -0,0 +1,135 @@
+#!/usr/bin/env bash
+
+# ------------------------------------------------------------------------------
+# Java 应用运维脚本
+# @author Zhang Peng
+# ------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env preparation
+# load libs
+CURRENT_PATH=`dirname ${BASH_SOURCE[0]}`
+source ${CURRENT_PATH}/utils.sh
+
+# ------------------------------------------------------------------------------ functions
+
+stopServer() {
+ if [[ ! $1 ]]; then
+ printError "please input java app name"
+ return ${FAILED}
+ fi
+
+ local javaAppName=$1
+ local pid=`jps | grep ${javaAppName} | awk '{print $1}'`
+ if [[ -n "${pid}" ]]; then
+ kill -9 ${pid}
+ if [[ $? -eq ${SUCCEED} ]]; then
+ printInfo "stop ${javaAppName} succeed"
+ return ${SUCCEED}
+ else
+ printError "stop ${javaAppName} failed"
+ return ${FAILED}
+ fi
+ else
+ printWarn "${javaAppName} is not running"
+ return ${SUCCEED}
+ fi
+}
+
+startServer() {
+ if [[ ! $1 ]]; then
+ printError "please input java app name"
+ return ${FAILED}
+ fi
+
+ # >>>> 1. check java app is started or not
+ # >>>> 1.1. exit script if the app is started
+ local javaAppName=$1
+ local pid=`jps | grep ${javaAppName} | awk '{print $1}'`
+ if [[ -n "${pid}" ]]; then
+ printInfo "${javaAppName} is started, PID: ${pid}"
+ return ${SUCCEED}
+ fi
+
+ # >>>> 2. package options
+ # GC OPTS
+ local javaOptions="-server -Xms1g -Xmx2g -Xss256k"
+ javaOptions="${javaOptions} -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:NewRatio=4"
+
+ # GC LOG OPTS
+ javaOptions="${javaOptions} -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps"
+ javaOptions="${javaOptions} -verbose:gc -Xloggc:${LOG_PATH}/${javaAppName}.gc.log"
+ javaOptions="${javaOptions} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
+
+ # Heap Dump OPTS
+ javaOptions="${javaOptions} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError"
+ javaOptions="${javaOptions} -XX:HeapDumpPath=${LOG_PATH}/${javaAppName}.heapdump.hprof"
+
+ # APP OPTS
+ javaOptions="${javaOptions} -Dsun.net.inetaddr.ttl=60 -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8"
+ if [[ ${PROFILE} ]]; then
+ javaOptions="${javaOptions} -Dspring.profiles.active=${PROFILE}"
+ fi
+
+ # DEBUG OPTS
+ if [[ "${DEBUG}" == "on" ]]; then
+ # JMX OPTS
+ local ip=$(ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d '/')
+ local jmxPort=$(expr 10000 + ${PORT})
+ javaOptions="${javaOptions} -Dcom.sun.management.jmxremote=true"
+ javaOptions="${javaOptions} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
+ javaOptions="${javaOptions} -Djava.rmi.server.hostname=${ip} -Dcom.sun.management.jmxremote.port=${jmxPort}"
+
+ # Remote Debug
+ local debugPort=$(expr 20000 + ${PORT})
+ javaOptions="${javaOptions} -Xdebug -Xnoagent -Djava.compiler=NONE"
+ javaOptions="${javaOptions} -Xrunjdwp:transport=dt_socket,address=${debugPort},server=y,suspend=n"
+ fi
+
+ # CLASSPATH
+ local appOptions="-classpath ${ROOT_PATH}/lib/* -Dlogging.config=file:${ROOT_PATH}/config/logback.dev.xml"
+ appOptions="${appOptions} --spring.config.location=classpath:/,classpath:/config/,file:${ROOT_PATH},file:${ROOT_PATH}/config/"
+ if [[ ${PORT} ]]; then
+ appOptions="${appOptions} --server.port=${PORT}"
+ fi
+
+ # >>>> 3. create log dir and console log file
+ mkdir -p ${LOG_PATH}
+ if [[ ! -x ${CONSOLE_LOG} ]]; then
+ touch ${CONSOLE_LOG}
+ fi
+
+ # >>>> 4. start java app
+ printInfo "starting ${javaAppName}, execute cli: "
+ printInfo "nohup java ${javaOptions} -jar ${ROOT_PATH}/${javaAppName}.jar ${appOptions} >> ${CONSOLE_LOG} 2>&1 &"
+ nohup java ${javaOptions} -jar ${ROOT_PATH}/${javaAppName}.jar ${appOptions} >> ${CONSOLE_LOG} 2>&1 &
+
+ # >>>> 5. check java app is started or not
+ local pid=`jps | grep ${javaAppName} | awk '{print $1}'`
+ if [[ -n "${pid}" ]]; then
+ printInfo "start ${javaAppName} succeed, PID: ${pid}"
+ return ${SUCCEED}
+ else
+ printError "start ${javaAppName} failed"
+ return ${FAILED}
+ fi
+}
+
+# ------------------------------------------------------------------------------ main
+export LANG="zh_CN.UTF-8"
+ROOT_PATH=$(cd ${CURRENT_PATH}/..; pwd)
+
+APP_NAME=java-app
+LOG_PATH=/var/log/myapp
+CONSOLE_LOG=${LOG_PATH}/${APP_NAME}.console.log
+
+PORT=8888
+PROFILE=dev
+DEBUG=off
+
+startServer ${APP_NAME}
+#stopServer ${APP_NAME}
+if [[ $? -eq ${SUCCEED} ]]; then
+ exit ${SUCCEED}
+else
+ exit ${FAILED}
+fi
diff --git a/codes/linux/soft/lib/maven.sh b/codes/linux/soft/lib/maven.sh
new file mode 100644
index 00000000..b55907fa
--- /dev/null
+++ b/codes/linux/soft/lib/maven.sh
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# maven operation utils
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ load libs
+
+LINUX_SCRIPTS_LIB_DIR=`dirname ${BASH_SOURCE[0]}`
+
+if [[ ! -x ${LINUX_SCRIPTS_LIB_DIR}/utils.sh ]]; then
+ echo "${LINUX_SCRIPTS_LIB_DIR}/utils.sh not exists!"
+ exit 1
+fi
+
+source ${LINUX_SCRIPTS_LIB_DIR}/utils.sh
+
+
+# ------------------------------------------------------------------------------ functions
+
+# execute maven lifecycle operation
+# @param $1: maven project path
+# @param $2: maven lifecycle, eg. package、install、deploy
+# @param $3: maven profile [optional]
+mavenOperation() {
+ local source=$1
+ local lifecycle=$2
+ local profile=$3
+
+ mavenCheck ${source}
+ if [[ "${ENV_SUCCEED}" != "$?" ]]; then
+ return ${ENV_FAILED}
+ fi
+
+ if [[ ! "${lifecycle}" ]]; then
+ logError "please input maven lifecycle"
+ return ${ENV_FAILED}
+ fi
+
+ local mvnCli="mvn clean ${lifecycle} -DskipTests=true -B -U"
+
+ if [[ ${profile} ]]; then
+ mvnCli="${mvnCli} -P${profile}"
+ fi
+
+ cd ${source}
+ if [[ -f "${source}/settings.xml" ]]; then
+ mvnCli="${mvnCli} -s ${source}/settings.xml"
+ fi
+
+ callAndLog "${mvnCli}"
+ cd -
+ return ${ENV_SUCCEED}
+}
+
+# check specified path is maven project or not
+# @param $1: maven project path
+mavenCheck() {
+ local source=$1
+ if [[ -d "${source}" ]]; then
+ cd ${source}
+ if [[ -f "${source}/pom.xml" ]]; then
+ return ${ENV_YES}
+ else
+ logError "pom.xml is not exists"
+ return ${ENV_NO}
+ fi
+ cd -
+ return ${ENV_YES}
+ else
+ logError "please input valid maven project path"
+ return ${ENV_NO}
+ fi
+}
diff --git a/codes/linux/soft/lib/mysql.sh b/codes/linux/soft/lib/mysql.sh
new file mode 100644
index 00000000..27e5cbdd
--- /dev/null
+++ b/codes/linux/soft/lib/mysql.sh
@@ -0,0 +1,233 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# 数据库操作脚本
+# 支持操作:
+# 备份 Mysql
+# 恢复 Mysql
+# @author: Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env
+
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+# ------------------------------------------------------------------------------ functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ printInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ printError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
+
+# ------------------------------------------------------------------------------ env
+
+# Mysql 操作的环境变量,使用方法:
+# 可以在执行本脚本之前,export 以下环境变量,否则将按照默认配置执行
+
+# Mysql HOST(默认为 127.0.0.1)
+ENV_MYSQL_HOST="${ENV_MYSQL_HOST:-127.0.0.1}"
+# Mysql 端口(默认为 3306)
+ENV_MYSQL_PORT=${ENV_MYSQL_PORT:-3306}
+# Mysql 用户名(默认为 root)
+ENV_MYSQL_USERNAME=${ENV_MYSQL_USERNAME:-root}
+# Mysql 密码(默认为 root)
+ENV_MYSQL_PASSWORD=${ENV_MYSQL_PASSWORD:-root}
+# Mysql 备份文件最大数量(默认为 7 天)
+ENV_BACKUP_MAX_NUM=${ENV_BACKUP_MAX_NUM:-7}
+
+# 备份模式:备份所有数据库(--all-databases)|备份指定数据库列表
+ENV_MYSQL_DATABASES="${ENV_MYSQL_DATABASES:---all-databases}"
+# 备份路径
+ENV_MYSQL_BACKUP_DIR="${ENV_MYSQL_BACKUP_DIR:-/var/lib/mysql/backup}"
+# 备份日志路径
+ENV_MYSQL_BACKUP_LOG_PATH="${ENV_MYSQL_BACKUP_DIR}/mysql-backup.log"
+
+magentaOutput "------------------------------------------------------------------------------"
+magentaOutput "Mysql 脚本操作环境变量:"
+magentaOutput "ENV_MYSQL_HOST:${ENV_MYSQL_HOST}"
+magentaOutput "ENV_MYSQL_PORT:${ENV_MYSQL_PORT}"
+magentaOutput "ENV_MYSQL_USERNAME:${ENV_MYSQL_USERNAME}"
+magentaOutput "ENV_MYSQL_PASSWORD:${ENV_MYSQL_PASSWORD}"
+magentaOutput "ENV_BACKUP_MAX_NUM:${ENV_BACKUP_MAX_NUM}"
+magentaOutput "ENV_MYSQL_DATABASES:${ENV_MYSQL_DATABASES}"
+magentaOutput "ENV_MYSQL_BACKUP_DIR:${ENV_MYSQL_BACKUP_DIR}"
+magentaOutput "ENV_MYSQL_BACKUP_LOG_PATH:${ENV_MYSQL_BACKUP_LOG_PATH}"
+magentaOutput "------------------------------------------------------------------------------"
+
+
+# ------------------------------------------------------------------------------ functions
+
+# 备份所有 database(schema)
+backupAllDatabase() {
+
+ #时间戳
+ local timestamp=$(date +"%Y%m%d")
+
+ #备份所有数据库
+ printInfo ">>>> 备份所有数据库开始"
+ mysqldump -h ${ENV_MYSQL_HOST} -P${ENV_MYSQL_PORT} -u${ENV_MYSQL_USERNAME} -p${ENV_MYSQL_PASSWORD} --all-databases > "${ENV_MYSQL_BACKUP_DIR}/all-${timestamp}.sql" 2>> ${ENV_MYSQL_BACKUP_LOG_PATH};
+
+ #检查备份结果是否成功
+ if [[ "$?" != ${ENV_SUCCEED} ]]; then
+ printError "<<<< 备份所有数据库失败"
+ return ${ENV_FAILED}
+ fi
+
+ # 压缩备份sql文件,删除旧的备份文件
+ cd "${ENV_MYSQL_BACKUP_DIR}"
+ if [[ ! -f "${ENV_MYSQL_BACKUP_DIR}/all-${timestamp}.sql" ]]; then
+ printError "备份文件 ${ENV_MYSQL_BACKUP_DIR}/all-${timestamp}.sql 不存在"
+ return ${ENV_FAILED}
+ fi
+ #为节约硬盘空间,将数据库压缩
+ tar zcf "all-${timestamp}.tar.gz" "all-${timestamp}.sql" > /dev/null
+ #删除原始文件,只留压缩后文件
+ rm -f "all-${timestamp}.sql"
+ #只保存期限内的备份文件,其余删除
+ find "${ENV_MYSQL_BACKUP_DIR} -name all-*.tar.gz -type f -mtime +${ENV_BACKUP_MAX_NUM} -exec rm -rf {} \;" > /dev/null 2>&1
+
+ printInfo "<<<< 备份所有数据库成功\n"
+ return ${ENV_SUCCEED}
+}
+
+# 备份指定的 database(schema)
+backupSelectedDatabase() {
+
+ #时间戳
+ local timestamp=$(date +"%Y%m%d")
+
+ #数据库,如有多个库用空格分开
+ databaseList="${ENV_MYSQL_DATABASES}"
+
+ #备份指定数据库列表
+ printInfo ">>>> 备份指定数据库开始"
+ for database in ${databaseList}; do
+
+ printInfo "正在备份数据库:${database}"
+ mysqldump -h ${ENV_MYSQL_HOST} -P${ENV_MYSQL_PORT} -u${ENV_MYSQL_USERNAME} -p${ENV_MYSQL_PASSWORD} "${database}" > "${ENV_MYSQL_BACKUP_DIR}/${database}-${timestamp}.sql" 2>> ${ENV_MYSQL_BACKUP_LOG_PATH};
+ if [[ "$?" != 0 ]]; then
+ printError "<<<< 备份 ${database} 失败"
+ return ${ENV_FAILED}
+ fi
+
+ # 压缩备份sql文件,删除旧的备份文件
+ cd "${ENV_MYSQL_BACKUP_DIR}"
+ if [[ ! -f "${ENV_MYSQL_BACKUP_DIR}/${database}-${timestamp}.sql" ]]; then
+ printError "备份文件 ${ENV_MYSQL_BACKUP_DIR}/${database}-${timestamp}.sql 不存在"
+ return ${ENV_FAILED}
+ fi
+ #为节约硬盘空间,将数据库压缩
+ tar zcf "${database}-${timestamp}.tar.gz" "${database}-${timestamp}.sql" > /dev/null
+ #删除原始文件,只留压缩后文件
+ rm -f "${database}-${timestamp}.sql"
+ #只保存期限内的备份文件,其余删除
+ find "${ENV_MYSQL_BACKUP_DIR} -name ${database}-*.tar.gz -type f -mtime +${ENV_BACKUP_MAX_NUM} -exec rm -rf {} \;" > /dev/null 2>&1
+ done
+
+ printInfo "<<<< 备份数据库 ${ENV_MYSQL_DATABASES} 成功\n"
+ return ${ENV_SUCCEED}
+}
+
+# 备份 Mysql
+backupMysql() {
+ #创建备份目录及日志文件
+ mkdir -p ${ENV_MYSQL_BACKUP_DIR}
+ if [[ ! -f ${ENV_MYSQL_BACKUP_LOG_PATH} ]]; then
+ touch ${ENV_MYSQL_BACKUP_LOG_PATH}
+ fi
+
+ #正式备份数据库
+ if [[ ${ENV_MYSQL_DATABASES} == "--all-databases" ]]; then
+ backupAllDatabase
+ else
+ backupSelectedDatabase
+ fi
+}
+
+# 恢复 Mysql
+recoveryMysql() {
+ #创建备份目录及日志文件
+ mkdir -p ${ENV_MYSQL_BACKUP_DIR}
+ if [[ ! -f ${ENV_MYSQL_BACKUP_LOG_PATH} ]]; then
+ touch ${ENV_MYSQL_BACKUP_LOG_PATH}
+ fi
+
+ printInfo ">>>> 恢复数据库开始"
+
+ mysql -h ${ENV_MYSQL_HOST} -P${ENV_MYSQL_PORT} -u${ENV_MYSQL_USERNAME} -p${ENV_MYSQL_PASSWORD} < ${ENV_MYSQL_BACKUP_LOG_PATH}
+ if [[ "$?" != 0 ]]; then
+ printError "<<<< 恢复数据库失败"
+ return ${ENV_FAILED}
+ fi
+
+ printInfo "<<<< 恢复数据库成功\n"
+ return ${ENV_SUCCEED}
+}
diff --git a/codes/linux/soft/lib/net.sh b/codes/linux/soft/lib/net.sh
new file mode 100644
index 00000000..ce8dbd3f
--- /dev/null
+++ b/codes/linux/soft/lib/net.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+# ----------------------------------------------------------------------------------
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+# ----------------------------------------------------------------------------------
+
+printf "${PURPLE}"
+cat << EOF
+# ----------------------------------------------------------------------------------
+# XXX 脚本
+# @author: Zhang Peng
+# ----------------------------------------------------------------------------------
+EOF
+printf "${RESET}"
+
+printf "${BLUE}>>>>>>>> begin.\n${RESET}"
+
+printf "${GREEN}[OK]\n${RESET}"
+printf "${RED}[ERROR]\n${RESET}"
+
+printf "${BLUE}<<<<<<<< end.\n${RESET}"
+
+IP=`ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d '/'`
diff --git a/codes/linux/soft/lib/nodejs.sh b/codes/linux/soft/lib/nodejs.sh
new file mode 100644
index 00000000..38d3849e
--- /dev/null
+++ b/codes/linux/soft/lib/nodejs.sh
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+
+# 装载其它库
+ROOT=`dirname ${BASH_SOURCE[0]}`
+source ${ROOT}/file.sh
+
+# ------------------------------------------------------------------------------ nodejs 操作函数
+
+# install Node Version Manager(nvm)
+installNvm() {
+ local nvmVersion=0.35.2
+ if [[ $1 ]]; then
+ local nvmVersion=$1
+ fi
+
+ recreateDir "~/.nvm"
+ curl -o- https://raw.githubusercontent.com/creationix/nvm/v${nvmVersion}/install.sh | bash
+ source ~/.nvm/nvm.sh
+ if [[ "$?" != "${YES}" ]]; then
+ return ${FAILED}
+ fi
+
+ # Check
+ nvm version
+ if [[ "$?" != "${YES}" ]]; then
+ return ${FAILED}
+ fi
+ return ${SUCCEED}
+}
+
+# Check nodejs version
+checkNodejsVersion() {
+ if [[ ! $1 ]]; then
+ printf "${C_B_RED}<<<< please specified expect nodejs version.${C_RESET}\n"
+ return ${FAILED}
+ fi
+
+ local expectVersion=$1
+
+ source /root/.bashrc
+ local nodeVersion=$(nvm version)
+ if [[ "$?" != "${YES}" ]]; then
+ printf "${C_B_YELLOW}>>>> nvm not installed.${C_RESET}\n"
+
+ local nvmVersion=v0.35.2
+ installNvm "${nvmVersion}"
+ if [[ "$?" != "${SUCCEED}" ]]; then
+ return ${FAILED}
+ fi
+ nodeVersion=$(nvm version)
+ fi
+
+ if [[ "${nodeVersion}" != "v${expectVersion}" ]]; then
+ printf "${C_B_YELLOW}>>>> current nodejs version is ${nodeVersion}, not ${expectVersion}.${C_RESET}\n"
+ nvm install ${expectVersion}
+ nvm use ${expectVersion}
+ fi
+
+ return ${SUCCEED}
+}
+
+# build nodejs project
+buildNodejsProject() {
+ if [[ ! $1 ]]; then
+ printf "${C_B_RED}<<<< please input nodejs project path.${C_RESET}\n"
+ return ${FAILED}
+ fi
+
+ if [[ ! $2 ]]; then
+ printf "${C_B_RED}<<<< please input nodejs version.${C_RESET}\n"
+ return ${FAILED}
+ fi
+
+ isDirectory $1
+ if [[ "$?" != "${YES}" ]]; then
+ printf "${C_B_RED}<<<< $1 is not valid path.${C_RESET}\n"
+ return ${FAILED}
+ fi
+
+ local project=$1
+ local nodeVersion=$2
+ printf "${C_B_BLUE}>>>> build nodejs project $1 begin.${C_RESET}\n"
+ cd ${project} || (printf "${C_B_RED}<<<< ${project} is not exists.${C_RESET}\n" && exit 1)
+
+ checkNodejsVersion ${nodeVersion}
+
+ npm install
+ if [[ "$?" != "${YES}" ]]; then
+ printf "${C_B_RED}<<<< update dependencies failed.${C_RESET}\n"
+ return ${FAILED}
+ else
+ printf "${C_B_GREEN}>>>> update dependencies succeed.${C_RESET}\n"
+ fi
+
+ npm run build
+ if [[ "$?" != "${YES}" ]]; then
+ printf "${C_B_RED}<<<< build failed.${C_RESET}\n"
+ return ${FAILED}
+ else
+ printf "${C_B_GREEN}<<<< build succeed.${C_RESET}\n"
+ fi
+ return ${SUCCEED}
+}
+
+# package nodejs artifact dir (default is dist)
+packageDist() {
+ zip -o -r -q ${branch}.zip *
+}
diff --git a/codes/linux/soft/lib/string.sh b/codes/linux/soft/lib/string.sh
new file mode 100644
index 00000000..9a752796
--- /dev/null
+++ b/codes/linux/soft/lib/string.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+strIsEmpty() {
+ if [[ -z $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+strIsNotEmpty() {
+ if [[ -n $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+strIsBlank() {
+ if [[ ! $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+strIsNotBlank() {
+ if [[ $1 ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+strEquals() {
+ if [[ "$1" = "$2" ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
+strStartWith() {
+ if [[ "$1" == "$2*" ]]; then
+ return ${YES}
+ else
+ return ${NO}
+ fi
+}
+
diff --git a/codes/linux/soft/lib/utils.sh b/codes/linux/soft/lib/utils.sh
new file mode 100644
index 00000000..7370f364
--- /dev/null
+++ b/codes/linux/soft/lib/utils.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# Shell Utils
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env
+
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Underline Color
+export ENV_COLOR_U_BLACK="\033[4;30m"
+export ENV_COLOR_U_RED="\033[4;31m"
+export ENV_COLOR_U_GREEN="\033[4;32m"
+export ENV_COLOR_U_YELLOW="\033[4;33m"
+export ENV_COLOR_U_BLUE="\033[4;34m"
+export ENV_COLOR_U_MAGENTA="\033[4;35m"
+export ENV_COLOR_U_CYAN="\033[4;36m"
+export ENV_COLOR_U_WHITE="\033[4;37m"
+# Background Color
+export ENV_COLOR_BG_BLACK="\033[40m"
+export ENV_COLOR_BG_RED="\033[41m"
+export ENV_COLOR_BG_GREEN="\033[42m"
+export ENV_COLOR_BG_YELLOW="\033[43m"
+export ENV_COLOR_BG_BLUE="\033[44m"
+export ENV_COLOR_BG_MAGENTA="\033[45m"
+export ENV_COLOR_BG_CYAN="\033[46m"
+export ENV_COLOR_BG_WHITE="\033[47m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+
+# ------------------------------------------------------------------------------ functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+# 日志路径
+LOG_PATH=${ENV_LOG_PATH:-/var/log/shell.log}
+# 日志目录
+LOG_DIR=${LOG_PATH%/*}
+
+createLogFileIfNotExists() {
+ if [[ ! -x "${LOG_PATH}" ]]; then
+ mkdir -p "${LOG_DIR}"
+ touch "${LOG_PATH}"
+ fi
+}
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
+
+logInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [INFO] [$0] $@" >> "${LOG_PATH}"
+}
+logWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [WARN] [$0] $@" >> "${LOG_PATH}"
+}
+logError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+ createLogFileIfNotExists
+ echo "[${SHELL_LOG_TIMESTAMP}] [${USER}] [ERROR] [$0] $@" >> "${LOG_PATH}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ logInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ logError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
diff --git a/codes/linux/soft/maven-install.sh b/codes/linux/soft/maven-install.sh
index f6983520..47e62662 100644
--- a/codes/linux/soft/maven-install.sh
+++ b/codes/linux/soft/maven-install.sh
@@ -28,23 +28,26 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install maven begin.${RESET}\n"
-command -v java >/dev/null 2>&1 || { printf "${RED}Require java but it's not installed.${RESET}\n"; exit 1; }
+command -v java > /dev/null 2>&1 || {
+ printf "${RED}Require java but it's not installed.${RESET}\n";
+ exit 1;
+}
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- printf "${PURPLE}[Hint]\n"
- printf "\t sh maven-install.sh [version] [path]\n"
- printf "\t Example: sh maven-install.sh 3.6.0 /opt/maven\n"
- printf "${RESET}\n"
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t sh maven-install.sh [version] [path]\n"
+ printf "\t Example: sh maven-install.sh 3.6.0 /opt/maven\n"
+ printf "${RESET}\n"
fi
-version=3.6.0
+version=3.5.4
if [[ -n $1 ]]; then
- version=$1
+ version=$1
fi
path=/opt/maven
if [[ -n $2 ]]; then
- path=$2
+ path=$2
fi
# install info
@@ -55,7 +58,7 @@ printf "${RESET}\n"
# download and decompression
mkdir -p ${path}
-wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" -O ${path}/apache-maven-${version}-bin.tar.gz http://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/${version}/binaries/apache-maven-${version}-bin.tar.gz
+wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" -O ${path}/apache-maven-${version}-bin.tar.gz http://apache.01link.hk/maven/maven-3/${version}/binaries/apache-maven-${version}-bin.tar.gz
tar -zxvf ${path}/apache-maven-${version}-bin.tar.gz -C ${path}
# setting env
diff --git a/codes/linux/soft/mongodb-install.sh b/codes/linux/soft/mongodb-install.sh
index ad17a63c..4f39bb4d 100644
--- a/codes/linux/soft/mongodb-install.sh
+++ b/codes/linux/soft/mongodb-install.sh
@@ -26,21 +26,21 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install mongodb begin.${RESET}\n"
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- printf "${PURPLE}[Hint]\n"
- printf "\t sh mongodb-install.sh [version] [path]\n"
- printf "\t Example: sh mongodb-install.sh 4.0.9 /opt/mongodb\n"
- printf "${RESET}\n"
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t sh mongodb-install.sh [version] [path]\n"
+ printf "\t Example: sh mongodb-install.sh 4.0.9 /opt/mongodb\n"
+ printf "${RESET}\n"
fi
version=4.0.9
if [[ -n $1 ]]; then
- version=$1
+ version=$1
fi
path=/opt/mongodb
if [[ -n $2 ]]; then
- path=$2
+ path=$2
fi
# install info
diff --git a/codes/linux/soft/mysql-backup.sh b/codes/linux/soft/mysql-backup.sh
new file mode 100644
index 00000000..2e6e9cfa
--- /dev/null
+++ b/codes/linux/soft/mysql-backup.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# Mysql 备份脚本
+# 可以通过 crond 服务,设置称为定时执行脚本:
+# (1)执行 crontab -e 编辑定时执行任务,如:59 23 * * * /home/scripts/mysql-backup.sh
+# (2)vi /etc/crontab,编辑 crontab 文件后保存,可以通过 crontab -l 查看
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env
+# Mysql Host
+export ENV_MYSQL_HOST="127.0.0.1"
+# Mysql 端口
+export ENV_MYSQL_PORT=3306
+# Mysql 用户名
+export ENV_MYSQL_USERNAME=root
+# Mysql 密码
+export ENV_MYSQL_PASSWORD=root
+# Mysql 备份文件最大数量
+export ENV_BACKUP_MAX_NUM=7
+# 备份模式:备份所有数据库(--all-databases)|备份指定数据库列表
+export ENV_MYSQL_DATABASES=--all-databases
+# 备份路径
+export ENV_MYSQL_BACKUP_DIR=/var/lib/mysql/backup
+# 备份日志路径
+export ENV_LOG_PATH="${ENV_MYSQL_BACKUP_DIR}/mysql-backup.log"
+
+# ------------------------------------------------------------------------------ libs
+LINUX_SCRIPTS_LIB_DIR=`dirname ${BASH_SOURCE[0]}`
+if [[ ! -x ${LINUX_SCRIPTS_LIB_DIR}/lib/mysql.sh ]]; then
+ echo "${LINUX_SCRIPTS_LIB_DIR}/lib/mysql.sh not exists!"
+ exit 1
+fi
+source ${LINUX_SCRIPTS_LIB_DIR}/lib/mysql.sh
+
+# ------------------------------------------------------------------------------ main
+# 执行备份方法
+backupMysql
diff --git a/codes/linux/soft/mysql-install.sh b/codes/linux/soft/mysql-install.sh
index 066e4edd..77fbb2cb 100644
--- a/codes/linux/soft/mysql-install.sh
+++ b/codes/linux/soft/mysql-install.sh
@@ -1,45 +1,145 @@
#!/usr/bin/env bash
-###################################################################################
-# 控制台颜色
-BLACK="\033[1;30m"
-RED="\033[1;31m"
-GREEN="\033[1;32m"
-YELLOW="\033[1;33m"
-BLUE="\033[1;34m"
-PURPLE="\033[1;35m"
-CYAN="\033[1;36m"
-RESET="$(tput sgr0)"
-###################################################################################
-
-printf "${BLUE}"
-cat << EOF
-
-###################################################################################
-# 安装 mysql 脚本
-# @system: 适用于 Centos7 发行版本。
+# -----------------------------------------------------------------------------------------------------
+# 安装 Mysql 脚本
+# 仅适用于 CentOS7 发行版本
# @author: Zhang Peng
-###################################################################################
+# -----------------------------------------------------------------------------------------------------
-EOF
-printf "${RESET}"
+# ------------------------------------------------------------------------------ env
+
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
+
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+# ------------------------------------------------------------------------------ functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
+
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
-printf "${GREEN}>>>>>>>> install mysql begin.${RESET}\n"
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
-command -v wget >/dev/null 2>&1 || { printf "${RED}Require wget but it's not installed.${RESET}\n"; exit 1; }
-command -v rpm >/dev/null 2>&1 || { printf "${RED}Require rpm but it's not installed.${RESET}\n"; exit 1; }
-command -v yum >/dev/null 2>&1 || { printf "${RED}Require yum but it's not installed.${RESET}\n"; exit 1; }
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
-# 使用 rpm 安装 mysql
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ printInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ printError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
+
+# ------------------------------------------------------------------------------ main
+
+printInfo ">>>> install mysql begin"
+
+command -v wget > /dev/null 2>&1 || {
+ printError "Require wget but it's not installed"
+ exit 1;
+}
+command -v rpm > /dev/null 2>&1 || {
+ printError "Require rpm but it's not installed"
+ exit 1;
+}
+command -v yum > /dev/null 2>&1 || {
+ printError "Require yum but it's not installed"
+ exit 1;
+}
+
+printInfo ">>>> install mysql by rpm"
wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
sudo rpm -Uvh mysql80-community-release-el7-3.noarch.rpm
sudo yum install mysql-community-server
-# 设置开机启动
+printInfo ">>>> modify my.cnf"
+cp /etc/my.cnf /etc/my.cnf.bak
+wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/config/mysql/my.cnf -O /etc/my.cnf
+
+printInfo ">>>> create mysql log file"
+mkdir -p /var/log/mysql
+touch /var/log/mysql/mysql.log
+touch /var/log/mysql/mysql_slow_query_log.log
+chmod 777 /var/log/mysql/mysql.log
+chmod 777 /var/log/mysql/mysql_slow_query_log.log
+chown -R mysql:mysql /var/log/mysql
+
+printInfo ">>>> modify limits.conf"
+cat >> /etc/security/limits.conf << EOF
+mysql soft nofile 65536
+mysql hard nofile 65536
+EOF
+
+printInfo ">>>> start mysqld"
systemctl enable mysqld
+systemctl start mysqld
systemctl daemon-reload
-password=$(grep "password" /var/log/mysqld.log | awk '{print $NF}')
-printf "临时密码为:${PURPLE}${password}${RESET},请登录 mysql 后重置新密码\n"
+printInfo ">>>> 管理员密码如下,请登录 mysql 后重置新密码:"
+password=$(grep "password" /var/log/mysql/mysql.log | awk '{print $NF}')
+blueOutput "${password}"
-printf "${GREEN}<<<<<<<< install mysql end.${RESET}\n"
+printInfo "<<<< install mysql success"
diff --git a/codes/linux/soft/mysql-recovery.sh b/codes/linux/soft/mysql-recovery.sh
new file mode 100644
index 00000000..eb7bf412
--- /dev/null
+++ b/codes/linux/soft/mysql-recovery.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+# -----------------------------------------------------------------------------------------------------
+# MYSQL 恢复脚本
+# @author Zhang Peng
+# -----------------------------------------------------------------------------------------------------
+
+# ------------------------------------------------------------------------------ env
+# Mysql Host
+export ENV_MYSQL_HOST="127.0.0.1"
+# Mysql 端口
+export ENV_MYSQL_PORT=3306
+# Mysql 用户名
+export ENV_MYSQL_USERNAME=root
+# Mysql 密码
+export ENV_MYSQL_PASSWORD=root
+# Mysql 备份文件最大数量
+export ENV_BACKUP_MAX_NUM=7
+# 备份模式:备份所有数据库(--all-databases)|备份指定数据库列表
+export ENV_MYSQL_DATABASES=--all-databases
+# 备份路径
+export ENV_MYSQL_BACKUP_DIR=/var/lib/mysql/backup
+# 备份日志路径
+export ENV_LOG_PATH="${ENV_MYSQL_BACKUP_DIR}/mysql-backup.log"
+
+# ------------------------------------------------------------------------------ libs
+LINUX_SCRIPTS_LIB_DIR=`dirname ${BASH_SOURCE[0]}`
+if [[ ! -x ${LINUX_SCRIPTS_LIB_DIR}/lib/mysql.sh ]]; then
+ echo "${LINUX_SCRIPTS_LIB_DIR}/lib/mysql.sh not exists!"
+ exit 1
+fi
+source ${LINUX_SCRIPTS_LIB_DIR}/lib/mysql.sh
+
+# ------------------------------------------------------------------------------ main
+# 执行备份方法
+recoveryMysql
diff --git a/codes/linux/soft/nacos-install.sh b/codes/linux/soft/nacos-install.sh
index 68bf8346..300a69c0 100644
--- a/codes/linux/soft/nacos-install.sh
+++ b/codes/linux/soft/nacos-install.sh
@@ -11,22 +11,28 @@ cat << EOF
EOF
-command -v java >/dev/null 2>&1 || { echo >&2 "Require java but it's not installed."; exit 1; }
-command -v mvn >/dev/null 2>&1 || { echo >&2 "Require mvn but it's not installed."; exit 1; }
-
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- echo "Usage: sh nacos-install.sh [version] [path]"
- printf "Example: sh nacos-install.sh 1.0.0 /opt/nacos\n"
+command -v java > /dev/null 2>&1 || {
+ printf "${RED}Require java but it's not installed.${RESET}\n";
+ exit 1;
+}
+command -v mvn > /dev/null 2>&1 || {
+ printf "${RED}Require mvn but it's not installed.${RESET}\n";
+ exit 1;
+}
+
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ echo "Usage: sh nacos-install.sh [version] [path]"
+ printf "Example: sh nacos-install.sh 1.0.0 /opt/nacos\n"
fi
version=1.0.0
if [[ -n $1 ]]; then
- version=$1
+ version=$1
fi
root=/opt/nacos
if [[ -n $2 ]]; then
- root=$2
+ root=$2
fi
echo "Current execution: install nacos ${version} to ${root}"
diff --git a/codes/linux/soft/nexus-install.sh b/codes/linux/soft/nexus-install.sh
index 1ec25401..75dbb876 100644
--- a/codes/linux/soft/nexus-install.sh
+++ b/codes/linux/soft/nexus-install.sh
@@ -1,18 +1,146 @@
#!/usr/bin/env bash
-###################################################################################
+# -----------------------------------------------------------------------------------------------------
# 安装 sonatype nexus(用于搭建 maven 私服) 脚本
# @system: 适用于所有 linux 发行版本。
# sonatype nexus 会被安装到 /opt/maven 路径。
# 注意:sonatype nexus 要求必须先安装 JDK
# @author: Zhang Peng
-###################################################################################
+# -----------------------------------------------------------------------------------------------------
-echo -e "\n>>>>>>>>> install sonatype nexus"
+# ------------------------------------------------------------------------------ env
-mkdir -p /opt/maven
-cd /opt/maven
+# Regular Color
+export ENV_COLOR_BLACK="\033[0;30m"
+export ENV_COLOR_RED="\033[0;31m"
+export ENV_COLOR_GREEN="\033[0;32m"
+export ENV_COLOR_YELLOW="\033[0;33m"
+export ENV_COLOR_BLUE="\033[0;34m"
+export ENV_COLOR_MAGENTA="\033[0;35m"
+export ENV_COLOR_CYAN="\033[0;36m"
+export ENV_COLOR_WHITE="\033[0;37m"
+# Bold Color
+export ENV_COLOR_B_BLACK="\033[1;30m"
+export ENV_COLOR_B_RED="\033[1;31m"
+export ENV_COLOR_B_GREEN="\033[1;32m"
+export ENV_COLOR_B_YELLOW="\033[1;33m"
+export ENV_COLOR_B_BLUE="\033[1;34m"
+export ENV_COLOR_B_MAGENTA="\033[1;35m"
+export ENV_COLOR_B_CYAN="\033[1;36m"
+export ENV_COLOR_B_WHITE="\033[1;37m"
+# Reset Color
+export ENV_COLOR_RESET="$(tput sgr0)"
-version=3.13.0-01
-curl -o /opt/maven/nexus-unix.tar.gz http://download.sonatype.com/nexus/3/nexus-${version}-unix.tar.gz
+# status
+export ENV_YES=0
+export ENV_NO=1
+export ENV_SUCCEED=0
+export ENV_FAILED=1
+
+# ------------------------------------------------------------------------------ functions
+
+# 显示打印日志的时间
+SHELL_LOG_TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
+# 那个用户在操作
+USER=$(whoami)
+
+redOutput() {
+ echo -e "${ENV_COLOR_RED} $@${ENV_COLOR_RESET}"
+}
+
+greenOutput() {
+ echo -e "${ENV_COLOR_B_GREEN} $@${ENV_COLOR_RESET}"
+}
+
+yellowOutput() {
+ echo -e "${ENV_COLOR_YELLOW} $@${ENV_COLOR_RESET}"
+}
+
+blueOutput() {
+ echo -e "${ENV_COLOR_BLUE} $@${ENV_COLOR_RESET}"
+}
+
+magentaOutput() {
+ echo -e "${ENV_COLOR_MAGENTA} $@${ENV_COLOR_RESET}"
+}
+
+cyanOutput() {
+ echo -e "${ENV_COLOR_CYAN} $@${ENV_COLOR_RESET}"
+}
+
+whiteOutput() {
+ echo -e "${ENV_COLOR_WHITE} $@${ENV_COLOR_RESET}"
+}
+
+printInfo() {
+ echo -e "${ENV_COLOR_B_GREEN}[INFO] $@${ENV_COLOR_RESET}"
+}
+
+printWarn() {
+ echo -e "${ENV_COLOR_B_YELLOW}[WARN] $@${ENV_COLOR_RESET}"
+}
+
+printError() {
+ echo -e "${ENV_COLOR_B_RED}[ERROR] $@${ENV_COLOR_RESET}"
+}
+
+callAndLog () {
+ $*
+ if [[ $? -eq ${ENV_SUCCEED} ]]; then
+ printInfo "$@"
+ return ${ENV_SUCCEED}
+ else
+ printError "$@ EXECUTE FAILED"
+ return ${ENV_FAILED}
+ fi
+}
+
+# ------------------------------------------------------------------------------ main
+ENV_NEXUS_VERSION=${ENV_NEXUS_VERSION:-3.13.0-01}
+ENV_NEXUS_DIR=${ENV_NEXUS_DIR:-/opt/maven}
+
+printInfo ">>>> install nexus begin."
+
+mkdir -p ${ENV_NEXUS_DIR}
+printInfo "download nexus"
+#由于国内网络问题,有可能下载失败
+curl -o ${ENV_NEXUS_DIR}/nexus-unix.tar.gz https://sonatype-download.global.ssl.fastly.net/repository/repositoryManager/3/nexus-${ENV_NEXUS_VERSION}-unix.tar.gz
+if [[ "$?" != ${ENV_SUCCEED} ]]; then
+ printError "<<<< download nexus-${ENV_NEXUS_VERSION}-unix.tar.gz failed"
+ return ${ENV_FAILED}
+fi
tar -zxf nexus-unix.tar.gz
+
+printInfo ">>>> setting systemd."
+#通过设置 systemd,是的 nexus 注册为服务,开机自启动
+touch /lib/systemd/system/nexus.service
+cat >> /lib/systemd/system/nexus.service << EOF
+[Unit]
+Description=nexus
+After=network.target
+
+[Service]
+Type=forking
+LimitNOFILE=65536 #警告处理
+Environment=RUN_AS_USER=root
+ExecStart=${ENV_NEXUS_DIR}/nexus-${ENV_NEXUS_VERSION}/bin/nexus start
+ExecReload=${ENV_NEXUS_DIR}/nexus-${ENV_NEXUS_VERSION}/bin/nexus restart
+ExecStop=${ENV_NEXUS_DIR}/nexus-${ENV_NEXUS_VERSION}/bin/nexus stop
+Restart=on-failure
+PrivateTmp=true
+
+[Install]
+WantedBy=multi-user.target
+EOF
+systemctl enable nexus
+systemctl start nexus
+
+printInfo ">>>> setting firewalld."
+firewall-cmd --zone=public --add-port=8081/tcp --permanent
+firewall-cmd --reload
+# 如果防火墻使用的是 iptables,使用如下配置:
+#iptables -I INPUT -p tcp -m tcp --dport 8081 -j ACCEPT
+#/etc/rc.d/init.d/iptables save
+#service iptables restart
+
+printInfo "<<<<<<<< install nexus success."
diff --git a/codes/linux/soft/nginx-install-by-rpm.sh b/codes/linux/soft/nginx-install-by-rpm.sh
deleted file mode 100644
index 07ea0834..00000000
--- a/codes/linux/soft/nginx-install-by-rpm.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-###################################################################################
-# 安装 nginx 脚本
-# 仅适用于 CentOS 发行版本。
-# @author: Zhang Peng
-###################################################################################
-
-echo -e "\n>>>>>>>>> install nginx"
-
-# Centos7 rpm 地址:http://nginx.org/packages/rhel/7/x86_64/RPMS/
-# CentOS6 rpm 地址:http://nginx.org/packages/rhel/6/x86_64/RPMS/
-
-mkdir -p /opt/nginx
-curl -o /opt/nginx/nginx.rpm http://nginx.org/packages/rhel/7/x86_64/RPMS/nginx-1.14.0-1.el7_4.ngx.x86_64.rpm
-rpm -ivh /opt/nginx/nginx.rpm
-nginx -v
diff --git a/codes/linux/soft/nginx-install-by-yum.sh b/codes/linux/soft/nginx-install-by-yum.sh
deleted file mode 100644
index bec957bb..00000000
--- a/codes/linux/soft/nginx-install-by-yum.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-
-###################################################################################
-# 安装 nginx 脚本
-# 仅适用于 CentOS 发行版本。
-# @author: Zhang Peng
-###################################################################################
-
-echo -e "\n>>>>>>>>> install nginx"
-
-yum -y install make nginx.x86_64
diff --git a/codes/linux/soft/nginx-install.sh b/codes/linux/soft/nginx-install.sh
index fd147904..0aa0ae68 100644
--- a/codes/linux/soft/nginx-install.sh
+++ b/codes/linux/soft/nginx-install.sh
@@ -12,67 +12,70 @@ CYAN="\033[1;36m"
RESET="$(tput sgr0)"
###################################################################################
-printf "${BLUE}"
+printf "${BLUE}\n"
cat << EOF
-
###################################################################################
-# 采用编译方式安装 nginx 脚本
-# nginx 会被安装到 /usr/local/nginx 路径。
-# @system: 适用于所有 linux 发行版本。
+# 采用编译方式安装 Nginx, 并将其注册为 systemd 服务
+# 默认下载安装 1.16.0 版本,安装路径为:/usr/local/nginx
+# @system: 适用于 CentOS7+
# @author: Zhang Peng
###################################################################################
-
EOF
-printf "${RESET}"
+printf "${RESET}\n"
-printf "${GREEN}>>>>>>>> install maven begin.${RESET}\n"
+command -v yum > /dev/null 2>&1 || {
+ printf "${RED}Require yum but it's not installed.${RESET}\n";
+ exit 1;
+}
-command -v yum >/dev/null 2>&1 || { printf "${RED}Require yum but it's not installed.${RESET}\n"; exit 1; }
+printf "\n${GREEN}>>>>>>>> install nginx begin${RESET}\n"
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- printf "${PURPLE}[Hint]\n"
- printf "\t sh nginx-install.sh [version] [path]\n"
- printf "\t Example: sh nginx-install.sh 1.16.0 /opt/nginx\n"
- printf "${RESET}\n"
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t Usage: sh nginx-install.sh [version] \n"
+ printf "\t Default: sh nginx-install.sh 1.16.0 \n"
+ printf "\t Example: sh nginx-install.sh 1.16.0 \n"
+ printf "${RESET}\n"
fi
+temp=/opt/nginx
version=1.16.0
if [[ -n $1 ]]; then
- version=$1
-fi
-
-path=/opt/nginx
-if [[ -n $2 ]]; then
- path=$2
+ version=$1
fi
# install info
-printf "${PURPLE}[Info]\n"
+printf "${PURPLE}[Install Info]\n"
printf "\t version = ${version}\n"
-printf "\t path = ${path}\n"
printf "${RESET}\n"
-printf "${GREEN}>>>>>>>> install required libs.${RESET}\n"
+printf "${CYAN}>>>> install required libs${RESET}\n"
yum install -y zlib zlib-devel gcc-c++ libtool openssl openssl-devel pcre
# download and decompression
-mkdir -p ${path}
-curl -o ${path}/nginx-${version}.tar.gz http://nginx.org/download/nginx-${version}.tar.gz
-tar zxf ${path}/nginx-${version}.tar.gz -C ${path}
+printf "${CYAN}>>>> download nginx${RESET}\n"
+mkdir -p ${temp}
+curl -o ${temp}/nginx-${version}.tar.gz http://nginx.org/download/nginx-${version}.tar.gz
+tar zxf ${temp}/nginx-${version}.tar.gz -C ${temp}
# configure and makefile
-cd ${path}/nginx-${version}
+printf "${CYAN}>>>> compile nginx${RESET}\n"
+cd ${temp}/nginx-${version}
./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-pcre
make && make install
+rm -rf ${temp}
+cd -
-# setting service
+# setting systemd service
+printf "${CYAN}>>>> set nginx as a systemd service${RESET}\n"
wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/config/nginx/nginx.service -O /usr/lib/systemd/system/nginx.service
chmod +x /usr/lib/systemd/system/nginx.service
-#设置nginx.service为系统服务
+
+# boot nginx
+printf "${CYAN}>>>> start nginx${RESET}\n"
systemctl enable nginx.service
-##通过系统服务操作nginx
systemctl start nginx.service
-#systemctl reload nginx.service
-#systemctl restart nginx.service
-#systemctl stop nginx.service
-printf "${GREEN}<<<<<<<< install nginx end.${RESET}\n"
+
+printf "\n${GREEN}<<<<<<<< install nginx end${RESET}\n"
+printf "\n${PURPLE}nginx service status: ${RESET}\n"
+systemctl status nginx
diff --git a/codes/linux/soft/nodejs-install.sh b/codes/linux/soft/nodejs-install.sh
index 9a84b9b0..9894c3a2 100644
--- a/codes/linux/soft/nodejs-install.sh
+++ b/codes/linux/soft/nodejs-install.sh
@@ -27,16 +27,16 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install nodejs begin.${RESET}\n"
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- printf "${PURPLE}[Hint]\n"
- printf "\t sh nodejs-install.sh [version]\n"
- printf "\t Example: sh nodejs-install.sh 10.15.2\n"
- printf "${RESET}\n"
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t sh nodejs-install.sh [version]\n"
+ printf "\t Example: sh nodejs-install.sh 10.15.2\n"
+ printf "${RESET}\n"
fi
version=10.15.2
if [[ -n $1 ]]; then
- version=$1
+ version=$1
fi
# install info
diff --git a/codes/linux/soft/redis-install.sh b/codes/linux/soft/redis-install.sh
index 07c0d430..b391568c 100644
--- a/codes/linux/soft/redis-install.sh
+++ b/codes/linux/soft/redis-install.sh
@@ -1,73 +1,106 @@
#!/usr/bin/env bash
+###################################################################################
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+##########################################################################cd#########
+
+printf "${BLUE}\n"
cat << EOF
-
###################################################################################
-# 安装 Redis 脚本
-# @system: 适用于 CentOS
+# 采用编译方式安装 Redis
+# @system: 适用于 CentOS7+
# @author: Zhang Peng
###################################################################################
-
EOF
+printf "${RESET}\n"
-command -v yum >/dev/null 2>&1 || { printf "${RED}Require yum but it's not installed.${RESET}\n"; exit 1; }
+command -v yum > /dev/null 2>&1 || {
+ printf "${RED}Require yum but it's not installed.${RESET}\n";
+ exit 1;
+}
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]] || [[ $# -lt 3 ]] || [[ $# -lt 4 ]];then
- echo "Usage: sh redis-install.sh [version] [path] [port] [password]"
- echo -e "Example: sh redis-install.sh 5.0.4 /opt/redis 6379 123456\n"
+printf "\n${GREEN}>>>>>>>> install redis begin${RESET}\n"
+
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]] || [[ $# -lt 3 ]] || [[ $# -lt 4 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t Usage: sh redis-install.sh [version] [port] [password] \n"
+ printf "\t Default: sh redis-install.sh 5.0.4 6379 \n"
+ printf "\t Example: sh redis-install.sh 5.0.4 6379 123456 \n"
+ printf "${RESET}\n"
fi
version=5.0.4
if [[ -n $1 ]]; then
- version=$1
+ version=$1
fi
-root=/opt/redis
+port=6379
if [[ -n $2 ]]; then
- root=$2
+ port=$2
fi
-port=6379
+password=
if [[ -n $3 ]]; then
- port=$3
+ password=$3
fi
-password=
-if [[ -n $4 ]]; then
- password=$4
-fi
+# install info
+printf "${PURPLE}[Install Info]\n"
+printf "\t version = ${version}\n"
+printf "\t port = ${port}\n"
+printf "\t password = ${password}\n"
+printf "${RESET}\n"
-echo "Current execution: install redis ${version} to ${root}, service port = ${port}, password = ${password}"
-echo -e "\n>>>>>>>>> install libs"
+printf "${CYAN}>>>> install required libs${RESET}\n"
yum install -y zlib zlib-devel gcc-c++ libtool openssl openssl-devel tcl
-echo -e "\n>>>>>>>>> download redis"
-mkdir -p ${root}
-curl -o ${root}/redis-${version}.tar.gz http://download.redis.io/releases/redis-${version}.tar.gz
-
-echo -e "\n>>>>>>>>> install redis"
-path=${root}/redis-${version}
-tar zxf ${root}/redis-${version}.tar.gz -C ${root}
+# download and decompression
+printf "${CYAN}>>>> download redis${RESET}\n"
+temp="/tmp/redis"
+path="/usr/local/redis"
+mkdir -p ${temp}
+curl -o ${temp}/redis-${version}.tar.gz http://download.redis.io/releases/redis-${version}.tar.gz
+tar zxf ${temp}/redis-${version}.tar.gz -C ${temp}
+mv ${temp}/redis-${version} ${path}
+
+# configure and makefile
+printf "${CYAN}>>>> compile redis${RESET}\n"
cd ${path}
make && make install
+rm -rf ${temp}
cd -
-echo -e "\n>>>>>>>>> config redis"
+printf "${CYAN}>>>> modify redis config${RESET}\n"
cp ${path}/redis.conf ${path}/redis.conf.default
-wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/config/redis-remote-access.conf -O ${path}/redis.conf
-cp ${path}/redis.conf /etc/redis/${port}.conf
-sed -i "s/^port 6379/port ${port}/g" /etc/redis/${port}.conf
-sed -i "s/^requirepass 123456/requirepass ${password}/g" /etc/redis/${port}.conf
+wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/config/redis/redis.conf -O ${path}/redis.conf
+sed -i "s/^port 6379/port ${port}/g" ${path}/redis.conf
+if [[ -n ${password} ]]; then
+ sed -i "s/^protected-mode no/protected-mode yes/g" ${path}/redis.conf
+ sed -i "s/^# requirepass/requirepass ${password}/g" ${path}/redis.conf
+fi
-echo -e "\n>>>>>>>>> add firewall port"
+printf "\n${CYAN}>>>> open redis port in firewall${RESET}\n"
firewall-cmd --zone=public --add-port=${port}/tcp --permanent
firewall-cmd --reload
-echo -e "\n>>>>>>>>> add redis service"
-# 注册 redis 服务,并设置开机自启动
-cp ${path}/utils/redis_init_script /etc/init.d/redis_${port}
-sed -i "s/^REDISPORT=.*/REDISPORT=${port}/g" /etc/init.d/redis_${port}
-chmod +x /etc/init.d/redis_${port}
-chkconfig --add redis_${port}
-service redis_${port} start
+# setting systemd service
+printf "${CYAN}>>>> set redis as a systemd service${RESET}\n"
+wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/config/redis/redis.service -O /usr/lib/systemd/system/redis.service
+chmod +x /usr/lib/systemd/system/redis.service
+
+# boot redis
+printf "${CYAN}>>>> start redis${RESET}\n"
+systemctl enable redis.service
+systemctl start redis.service
+printf "\n${GREEN}<<<<<<<< install redis end${RESET}\n"
+printf "\n${PURPLE}redis service status: ${RESET}\n"
+systemctl status redis
diff --git a/codes/linux/soft/rocketmq-install.sh b/codes/linux/soft/rocketmq-install.sh
index c7fe7710..10875113 100644
--- a/codes/linux/soft/rocketmq-install.sh
+++ b/codes/linux/soft/rocketmq-install.sh
@@ -26,21 +26,21 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install tomcat begin.${RESET}\n"
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- printf "${PURPLE}[Hint]\n"
- printf "\t sh rocketmq-install.sh [version] [path]\n"
- printf "\t Example: sh rocketmq-install.sh 4.5.0 /opt/rocketmq\n"
- printf "${RESET}\n"
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t sh rocketmq-install.sh [version] [path]\n"
+ printf "\t Example: sh rocketmq-install.sh 4.5.0 /opt/rocketmq\n"
+ printf "${RESET}\n"
fi
version=4.5.0
if [[ -n $1 ]]; then
- version=$1
+ version=$1
fi
path=/opt/rocketmq
if [[ -n $2 ]]; then
- path=$2
+ path=$2
fi
# install info
diff --git a/codes/linux/soft/tomcat8-install.sh b/codes/linux/soft/tomcat8-install.sh
index 0980b153..db76cda1 100644
--- a/codes/linux/soft/tomcat8-install.sh
+++ b/codes/linux/soft/tomcat8-install.sh
@@ -26,21 +26,21 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install tomcat begin.${RESET}\n"
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- printf "${PURPLE}[Hint]\n"
- printf "\t sh tomcat8-install.sh [version] [path]\n"
- printf "\t Example: sh tomcat8-install.sh 8.5.28 /opt/tomcat8\n"
- printf "${RESET}\n"
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t sh tomcat8-install.sh [version] [path]\n"
+ printf "\t Example: sh tomcat8-install.sh 8.5.28 /opt/tomcat8\n"
+ printf "${RESET}\n"
fi
version=8.5.28
if [[ -n $1 ]]; then
- version=$1
+ version=$1
fi
path=/opt/tomcat
if [[ -n $2 ]]; then
- path=$2
+ path=$2
fi
# install info
diff --git a/codes/linux/soft/zookeeper-install.sh b/codes/linux/soft/zookeeper-install.sh
index 2a8fe8fe..37fc5f46 100644
--- a/codes/linux/soft/zookeeper-install.sh
+++ b/codes/linux/soft/zookeeper-install.sh
@@ -26,21 +26,21 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install zookeeper begin.${RESET}\n"
-if [[ $# -lt 1 ]] || [[ $# -lt 2 ]];then
- printf "${PURPLE}[Hint]\n"
- printf "\t sh zookeeper-install.sh [version] [path]\n"
- printf "\t Example: sh zookeeper-install.sh 3.4.12 /opt/zookeeper\n"
- printf "${RESET}\n"
+if [[ $# -lt 1 ]] || [[ $# -lt 2 ]]; then
+ printf "${PURPLE}[Hint]\n"
+ printf "\t sh zookeeper-install.sh [version] [path]\n"
+ printf "\t Example: sh zookeeper-install.sh 3.4.12 /opt/zookeeper\n"
+ printf "${RESET}\n"
fi
version=3.4.12
if [[ -n $1 ]]; then
- version=$1
+ version=$1
fi
path=/opt/zookeeper
if [[ -n $2 ]]; then
- path=$2
+ path=$2
fi
# install info
diff --git a/codes/linux/soft/zsh-install.sh b/codes/linux/soft/zsh-install.sh
index 0831750e..df2300dc 100644
--- a/codes/linux/soft/zsh-install.sh
+++ b/codes/linux/soft/zsh-install.sh
@@ -27,14 +27,23 @@ printf "${RESET}"
printf "${GREEN}>>>>>>>> install zsh begin.${RESET}\n"
-command -v yum >/dev/null 2>&1 || { printf "${RED}Require yum but it's not installed.${RESET}\n"; exit 1; }
-command -v git >/dev/null 2>&1 || { printf "${RED}Require git but it's not installed.${RESET}\n"; exit 1; }
+command -v yum > /dev/null 2>&1 || {
+ printf "${RED}Require yum but it's not installed.${RESET}\n";
+ exit 1;
+}
+command -v git > /dev/null 2>&1 || {
+ printf "${RED}Require git but it's not installed.${RESET}\n";
+ exit 1;
+}
# install zsh
yum install -y zsh
chsh -s /bin/zsh
# install oh-my-zsh
-curl -o- https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh | bash
+# 由于国内经常无法使用 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
+# 所以,索性将安装脚本下载下来直接使用
+#curl -o- https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh | bash
+zsh/oh-my-zsh-install.sh
# choose oh-my-zsh theme
sed -i "s/^ZSH_THEME=.*/ZSH_THEME=\"ys\"/g" ~/.zshrc
# install oh-my-zsh plugins
@@ -42,6 +51,9 @@ git clone https://github.com/zsh-users/zsh-autosuggestions.git ~/.oh-my-zsh/plug
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ~/.oh-my-zsh/plugins/zsh-syntax-highlighting
sed -i "s/^plugins=.*/plugins=(git z wd extract zsh-autosuggestions zsh-syntax-highlighting)/g" ~/.zshrc
# reload zsh
-
+# 注册到 /etc/shells
+echo "/usr/bin/zsh" >> /etc/shells
+# 切换 shell
+chsh -s $(which zsh)
printf "${GREEN}<<<<<<<< install zsh finished${RESET}\n"
printf "${GREEN}Please reboot to take effect.${RESET}\n"
diff --git a/codes/linux/soft/zsh/oh-my-zsh-install.sh b/codes/linux/soft/zsh/oh-my-zsh-install.sh
new file mode 100644
index 00000000..ebf27522
--- /dev/null
+++ b/codes/linux/soft/zsh/oh-my-zsh-install.sh
@@ -0,0 +1,294 @@
+# -------------------------------------------------------------------------------------------------------------------
+# 由于国内经常无法使用 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
+# 所以,索性将安装脚本下载下来直接使用
+# -------------------------------------------------------------------------------------------------------------------
+
+#!/bin/sh
+#
+# This script should be run via curl:
+# sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
+# or wget:
+# sh -c "$(wget -qO- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
+#
+# As an alternative, you can first download the install script and run it afterwards:
+# wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh
+# sh install.sh
+#
+# You can tweak the install behavior by setting variables when running the script. For
+# example, to change the path to the Oh My Zsh repository:
+# ZSH=~/.zsh sh install.sh
+#
+# Respects the following environment variables:
+# ZSH - path to the Oh My Zsh repository folder (default: $HOME/.oh-my-zsh)
+# REPO - name of the GitHub repo to install from (default: ohmyzsh/ohmyzsh)
+# REMOTE - full remote URL of the git repo to install (default: GitHub via HTTPS)
+# BRANCH - branch to check out immediately after install (default: master)
+#
+# Other options:
+# CHSH - 'no' means the installer will not change the default shell (default: yes)
+# RUNZSH - 'no' means the installer will not run zsh after the install (default: yes)
+# KEEP_ZSHRC - 'yes' means the installer will not replace an existing .zshrc (default: no)
+#
+# You can also pass some arguments to the install script to set some these options:
+# --skip-chsh: has the same behavior as setting CHSH to 'no'
+# --unattended: sets both CHSH and RUNZSH to 'no'
+# --keep-zshrc: sets KEEP_ZSHRC to 'yes'
+# For example:
+# sh install.sh --unattended
+#
+set -e
+
+# Default settings
+ZSH=${ZSH:-~/.oh-my-zsh}
+REPO=${REPO:-ohmyzsh/ohmyzsh}
+REMOTE=${REMOTE:-https://github.com/${REPO}.git}
+BRANCH=${BRANCH:-master}
+
+# Other options
+CHSH=${CHSH:-yes}
+RUNZSH=${RUNZSH:-yes}
+KEEP_ZSHRC=${KEEP_ZSHRC:-no}
+
+
+command_exists() {
+ command -v "$@" >/dev/null 2>&1
+}
+
+error() {
+ echo ${RED}"Error: $@"${RESET} >&2
+}
+
+setup_color() {
+ # Only use colors if connected to a terminal
+ if [ -t 1 ]; then
+ RED=$(printf '\033[31m')
+ GREEN=$(printf '\033[32m')
+ YELLOW=$(printf '\033[33m')
+ BLUE=$(printf '\033[34m')
+ BOLD=$(printf '\033[1m')
+ RESET=$(printf '\033[m')
+ else
+ RED=""
+ GREEN=""
+ YELLOW=""
+ BLUE=""
+ BOLD=""
+ RESET=""
+ fi
+}
+
+setup_ohmyzsh() {
+ # Prevent the cloned repository from having insecure permissions. Failing to do
+ # so causes compinit() calls to fail with "command not found: compdef" errors
+ # for users with insecure umasks (e.g., "002", allowing group writability). Note
+ # that this will be ignored under Cygwin by default, as Windows ACLs take
+ # precedence over umasks except for filesystems mounted with option "noacl".
+ umask g-w,o-w
+
+ echo "${BLUE}Cloning Oh My Zsh...${RESET}"
+
+ command_exists git || {
+ error "git is not installed"
+ exit 1
+ }
+
+ if [ "$OSTYPE" = cygwin ] && git --version | grep -q msysgit; then
+ error "Windows/MSYS Git is not supported on Cygwin"
+ error "Make sure the Cygwin git package is installed and is first on the \$PATH"
+ exit 1
+ fi
+
+ git clone -c core.eol=lf -c core.autocrlf=false \
+ -c fsck.zeroPaddedFilemode=ignore \
+ -c fetch.fsck.zeroPaddedFilemode=ignore \
+ -c receive.fsck.zeroPaddedFilemode=ignore \
+ --depth=1 --branch "$BRANCH" "$REMOTE" "$ZSH" || {
+ error "git clone of oh-my-zsh repo failed"
+ exit 1
+ }
+
+ echo
+}
+
+setup_zshrc() {
+ # Keep most recent old .zshrc at .zshrc.pre-oh-my-zsh, and older ones
+ # with datestamp of installation that moved them aside, so we never actually
+ # destroy a user's original zshrc
+ echo "${BLUE}Looking for an existing zsh config...${RESET}"
+
+ # Must use this exact name so uninstall.sh can find it
+ OLD_ZSHRC=~/.zshrc.pre-oh-my-zsh
+ if [ -f ~/.zshrc ] || [ -h ~/.zshrc ]; then
+ # Skip this if the user doesn't want to replace an existing .zshrc
+ if [ $KEEP_ZSHRC = yes ]; then
+ echo "${YELLOW}Found ~/.zshrc.${RESET} ${GREEN}Keeping...${RESET}"
+ return
+ fi
+ if [ -e "$OLD_ZSHRC" ]; then
+ OLD_OLD_ZSHRC="${OLD_ZSHRC}-$(date +%Y-%m-%d_%H-%M-%S)"
+ if [ -e "$OLD_OLD_ZSHRC" ]; then
+ error "$OLD_OLD_ZSHRC exists. Can't back up ${OLD_ZSHRC}"
+ error "re-run the installer again in a couple of seconds"
+ exit 1
+ fi
+ mv "$OLD_ZSHRC" "${OLD_OLD_ZSHRC}"
+
+ echo "${YELLOW}Found old ~/.zshrc.pre-oh-my-zsh." \
+ "${GREEN}Backing up to ${OLD_OLD_ZSHRC}${RESET}"
+ fi
+ echo "${YELLOW}Found ~/.zshrc.${RESET} ${GREEN}Backing up to ${OLD_ZSHRC}${RESET}"
+ mv ~/.zshrc "$OLD_ZSHRC"
+ fi
+
+ echo "${GREEN}Using the Oh My Zsh template file and adding it to ~/.zshrc.${RESET}"
+
+ sed "/^export ZSH=/ c\\
+export ZSH=\"$ZSH\"
+" "$ZSH/templates/zshrc.zsh-template" > ~/.zshrc-omztemp
+ mv -f ~/.zshrc-omztemp ~/.zshrc
+
+ echo
+}
+
+setup_shell() {
+ # Skip setup if the user wants or stdin is closed (not running interactively).
+ if [ $CHSH = no ]; then
+ return
+ fi
+
+ # If this user's login shell is already "zsh", do not attempt to switch.
+ if [ "$(basename "$SHELL")" = "zsh" ]; then
+ return
+ fi
+
+ # If this platform doesn't provide a "chsh" command, bail out.
+ if ! command_exists chsh; then
+ cat <<-EOF
+ I can't change your shell automatically because this system does not have chsh.
+ ${BLUE}Please manually change your default shell to zsh${RESET}
+ EOF
+ return
+ fi
+
+ echo "${BLUE}Time to change your default shell to zsh:${RESET}"
+
+ # Prompt for user choice on changing the default login shell
+ printf "${YELLOW}Do you want to change your default shell to zsh? [Y/n]${RESET} "
+ read opt
+ case $opt in
+ y*|Y*|"") echo "Changing the shell..." ;;
+ n*|N*) echo "Shell change skipped."; return ;;
+ *) echo "Invalid choice. Shell change skipped."; return ;;
+ esac
+
+ # Check if we're running on Termux
+ case "$PREFIX" in
+ *com.termux*) termux=true; zsh=zsh ;;
+ *) termux=false ;;
+ esac
+
+ if [ "$termux" != true ]; then
+ # Test for the right location of the "shells" file
+ if [ -f /etc/shells ]; then
+ shells_file=/etc/shells
+ elif [ -f /usr/share/defaults/etc/shells ]; then # Solus OS
+ shells_file=/usr/share/defaults/etc/shells
+ else
+ error "could not find /etc/shells file. Change your default shell manually."
+ return
+ fi
+
+ # Get the path to the right zsh binary
+ # 1. Use the most preceding one based on $PATH, then check that it's in the shells file
+ # 2. If that fails, get a zsh path from the shells file, then check it actually exists
+ if ! zsh=$(which zsh) || ! grep -qx "$zsh" "$shells_file"; then
+ if ! zsh=$(grep '^/.*/zsh$' "$shells_file" | tail -1) || [ ! -f "$zsh" ]; then
+ error "no zsh binary found or not present in '$shells_file'"
+ error "change your default shell manually."
+ return
+ fi
+ fi
+ fi
+
+ # We're going to change the default shell, so back up the current one
+ if [ -n "$SHELL" ]; then
+ echo $SHELL > ~/.shell.pre-oh-my-zsh
+ else
+ grep "^$USER:" /etc/passwd | awk -F: '{print $7}' > ~/.shell.pre-oh-my-zsh
+ fi
+
+ # Actually change the default shell to zsh
+ if ! chsh -s "$zsh"; then
+ error "chsh command unsuccessful. Change your default shell manually."
+ else
+ export SHELL="$zsh"
+ echo "${GREEN}Shell successfully changed to '$zsh'.${RESET}"
+ fi
+
+ echo
+}
+
+main() {
+ # Run as unattended if stdin is closed
+ if [ ! -t 0 ]; then
+ RUNZSH=no
+ CHSH=no
+ fi
+
+ # Parse arguments
+ while [ $# -gt 0 ]; do
+ case $1 in
+ --unattended) RUNZSH=no; CHSH=no ;;
+ --skip-chsh) CHSH=no ;;
+ --keep-zshrc) KEEP_ZSHRC=yes ;;
+ esac
+ shift
+ done
+
+ setup_color
+
+ if ! command_exists zsh; then
+ echo "${YELLOW}Zsh is not installed.${RESET} Please install zsh first."
+ exit 1
+ fi
+
+ if [ -d "$ZSH" ]; then
+ cat <<-EOF
+ ${YELLOW}You already have Oh My Zsh installed.${RESET}
+ You'll need to remove '$ZSH' if you want to reinstall.
+ EOF
+ exit 1
+ fi
+
+ setup_ohmyzsh
+ setup_zshrc
+ setup_shell
+
+ printf "$GREEN"
+ cat <<-'EOF'
+ __ __
+ ____ / /_ ____ ___ __ __ ____ _____/ /_
+ / __ \/ __ \ / __ `__ \/ / / / /_ / / ___/ __ \
+ / /_/ / / / / / / / / / / /_/ / / /_(__ ) / / /
+ \____/_/ /_/ /_/ /_/ /_/\__, / /___/____/_/ /_/
+ /____/ ....is now installed!
+
+
+ Please look over the ~/.zshrc file to select plugins, themes, and options.
+
+ p.s. Follow us on https://twitter.com/ohmyzsh
+
+ p.p.s. Get stickers, shirts, and coffee mugs at https://shop.planetargon.com/collections/oh-my-zsh
+
+ EOF
+ printf "$RESET"
+
+ if [ $RUNZSH = no ]; then
+ echo "${YELLOW}Run zsh to try it out.${RESET}"
+ exit
+ fi
+
+ exec zsh -l
+}
+
+main "$@"
diff --git a/codes/linux/sys/README.md b/codes/linux/sys/README.md
index 29669281..e0bc15d0 100644
--- a/codes/linux/sys/README.md
+++ b/codes/linux/sys/README.md
@@ -19,7 +19,7 @@
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/yum/change-yum-repo.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/yum/change-yum-repo.sh | bash
```
@@ -44,7 +44,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/yum
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/install-tools.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/install-tools.sh | bash
```
@@ -62,7 +62,7 @@ lib 清单(可以根据需要,在 install-libs.sh 中把不需要的工具
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/install-libs.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/install-libs.sh | bash
```
@@ -71,7 +71,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/ins
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/stop-firewall.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/stop-firewall.sh | bash
```
@@ -80,7 +80,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/sto
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/set-dns.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/set-dns.sh | bash
```
@@ -89,7 +89,7 @@ wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/set
使用方法:执行以下任意命令即可执行脚本。
-```sh
+```shell
curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/set-ntp.sh | bash
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/set-ntp.sh | bash
```
diff --git a/codes/linux/sys/change-yum-repo.sh b/codes/linux/sys/change-yum-repo.sh
index 345c0c3d..65611c87 100644
--- a/codes/linux/sys/change-yum-repo.sh
+++ b/codes/linux/sys/change-yum-repo.sh
@@ -1,15 +1,28 @@
#!/usr/bin/env bash
+# ---------------------------------------------------------------------------------
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+# ---------------------------------------------------------------------------------
+
+printf "${BLUE}\n"
cat << EOF
###################################################################################
# 本脚本用于替换 yum repo,使用国内 yum 仓库,加速下载
# 要求:仅适用于 Linux CentOS 发行版本,并且环境必须已支持 yum 、lsb_release 命令
# @author: Zhang Peng
###################################################################################
-
EOF
+printf "${RESET}\n"
-echo -e "\n>>>>>>>>> 替换 yum repo 源"
+printf "\n${GREEN}>>>>>>>>> 替换 yum repo 源开始${RESET}\n"
# 备份
cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
@@ -18,29 +31,27 @@ cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
# version=`lsb_release -r | awk '{print substr($2,1,1)}'` # 很多机器没有 lsb_release 命令
version=`cat /etc/redhat-release | awk '{print substr($4,1,1)}'`
-cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
-
# 根据发型版本选择相应 yum 镜像
if [[ ${version} == 5 ]]; then
- # Cento5 已废弃,只能使用 http://vault.CentOS.org/ 替换,但由于是国外镜像,速度较慢
- wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/yum/Centos-5.repo -O /etc/yum.repos.d/CentOS-Base.repo
+ # Cento5 已废弃,只能使用 http://vault.CentOS.org/ 替换,但由于是国外镜像,速度较慢
+ wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/yum/Centos-5.repo -O /etc/yum.repos.d/CentOS-Base.repo
- # 根据实际发型版本情况替换
- detailVersion=`lsb_release -r | awk '{print substr($2,1,3)}'`
- sed -i 's/$releasever/'"${detailVersion}"'/g' /etc/yum.repos.d/CentOS-Base.repo
+ # 根据实际发型版本情况替换
+ detailVersion=`lsb_release -r | awk '{print substr($2,1,3)}'`
+ sed -i 's/$releasever/'"${detailVersion}"'/g' /etc/yum.repos.d/CentOS-Base.repo
- # 不替换下面的开关,可能会出现错误:Could not open/read repomd.xml
- sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/CentOS-Media.repo
+ # 不替换下面的开关,可能会出现错误:Could not open/read repomd.xml
+ sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/CentOS-Media.repo
elif [[ ${version} == 6 ]]; then
- wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/yum/Centos-6.repo -O /etc/yum.repos.d/CentOS-Base.repo
+ wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/yum/Centos-6.repo -O /etc/yum.repos.d/CentOS-Base.repo
elif [[ ${version} == 7 ]]; then
- wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/yum/Centos-7.repo -O /etc/yum.repos.d/CentOS-Base.repo
+ wget -N https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/yum/Centos-7.repo -O /etc/yum.repos.d/CentOS-Base.repo
else
- echo -e "版本不支持,替换 yum repo 失败"
+ printf "\n${RED}版本不支持,替换 yum repo 失败${RESET}\n"
fi
# 更新缓存
yum clean all
yum makecache
-echo -e "\n>>>>>>>>> 替换 yum repo 源成功"
+printf "\n${GREEN}<<<<<<<< 替换 yum repo 源结束${RESET}\n"
diff --git a/codes/linux/sys/install-libs.sh b/codes/linux/sys/install-libs.sh
index 02cec37b..8fc7d240 100644
--- a/codes/linux/sys/install-libs.sh
+++ b/codes/linux/sys/install-libs.sh
@@ -1,29 +1,45 @@
#!/usr/bin/env bash
-###################################################################################
-# 安装常见 lib
-# @author: Zhang Peng
-#
-# 如果不知道某个命令工具是由哪个包提供的,使用 yum provides xxx
-# 或 yum whatprovides xxx 来查找
-###################################################################################
+# ---------------------------------------------------------------------------------
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+# ---------------------------------------------------------------------------------
+printf "${BLUE}\n"
+cat << EOF
###################################################################################
-# 执行本脚本后支持的 lib 清单:
+# 安装常见 lib
+# 如果不知道命令在哪个 lib,可以使用 yum search xxx 来查找
+# lib 清单如下:
# gcc gcc-c++ kernel-devel libtool
# openssl openssl-devel
# zlib zlib-devel
# pcre
+#
+# @author: Zhang Peng
###################################################################################
+EOF
+printf "${RESET}\n"
-echo -e "\n>>>>>>>>> install gcc gcc-c++ kernel-devel libtool"
+printf "\n${GREEN}>>>>>>>>> 安装常见 lib 开始${RESET}\n"
+
+printf "\n${CYAN}>>>> install gcc gcc-c++ kernel-devel libtool${RESET}\n"
yum -y install make gcc gcc-c++ kernel-devel libtool
-echo -e "\n>>>>>>>>> install openssl openssl-devel"
+printf "\n${CYAN}>>>> install openssl openssl-devel${RESET}\n"
yum -y install make openssl openssl-devel
-echo -e "\n>>>>>>>>> install zlib zlib-devel"
+printf "\n${CYAN}>>>> install zlib zlib-devel${RESET}\n"
yum -y install make zlib zlib-devel
-echo -e "\n>>>>>>>>> install pcre"
+printf "\n${CYAN}>>>> install pcre${RESET}\n"
yum -y install pcre
+
+printf "\n${GREEN}<<<<<<<< 安装常见 lib 结束${RESET}\n"
diff --git a/codes/linux/sys/install-tools.sh b/codes/linux/sys/install-tools.sh
index 01f3d772..999898c0 100644
--- a/codes/linux/sys/install-tools.sh
+++ b/codes/linux/sys/install-tools.sh
@@ -1,19 +1,22 @@
#!/usr/bin/env bash
-cat << EOF
-###################################################################################
-# 安装基本的命令工具
-# @author: Zhang Peng
-#
-# 如果不知道某个命令工具是由哪个包提供的,使用 yum provides xxx
-# 或 yum whatprovides xxx 来查找
-###################################################################################
-
-EOF
+# ---------------------------------------------------------------------------------
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+# ---------------------------------------------------------------------------------
+printf "${BLUE}\n"
cat << EOF
###################################################################################
-# 执行本脚本后支持的命令工具清单:
+# 安装常用命令工具
+# 命令工具清单如下:
# 核心工具:df、du、chkconfig
# 网络工具:ifconfig、netstat、route、iptables
# IP工具:ip、ss、ping、tracepath、traceroute
@@ -25,72 +28,78 @@ cat << EOF
# 抓包工具:tcpdump
# 压缩工具:unzip、zip
# 版本控制工具:git、subversion
+#
+# @author: Zhang Peng
###################################################################################
-
EOF
+printf "${RESET}\n"
+
+printf "\n${GREEN}>>>>>>>>> 安装常用命令工具开始${RESET}\n"
# 核心工具
-echo -e "\n>>>>>>>>> install coreutils(df、du)"
+printf "\n${CYAN}>>>> install coreutils(df、du)${RESET}\n"
yum install -y coreutils
-echo -e "\n>>>>>>>>> install chkconfig"
+printf "\n${CYAN}>>>> install chkconfig${RESET}\n"
yum install -y chkconfig
# 网络工具
-echo -e "\n>>>>>>>>> install net-tools(ifconfig、netstat、route)"
+printf "\n${CYAN}>>>> install net-tools(ifconfig、netstat、route)${RESET}\n"
yum install -y net-tools
-echo -e "\n>>>>>>>>> install iptables"
+printf "\n${CYAN}>>>> install iptables${RESET}\n"
yum install -y iptables
# IP工具
-echo -e "\n>>>>>>>>> install iputils(ping、tracepath)"
+printf "\n${CYAN}>>>> install iputils(ping、tracepath)${RESET}\n"
yum install -y iputils
-echo -e "\n>>>>>>>>> install traceroute"
+printf "\n${CYAN}>>>> install traceroute${RESET}\n"
yum install -y traceroute
-echo -e "\n>>>>>>>>> install iproute(ip、ss)"
+printf "\n${CYAN}>>>> install iproute(ip、ss)${RESET}\n"
yum install -y iproute
# 端口工具
-echo -e "\n>>>>>>>>> install lsof"
+printf "\n${CYAN}>>>> install lsof${RESET}\n"
yum install -y lsof
-echo -e "\n>>>>>>>>> install nc"
+printf "\n${CYAN}>>>> install nc${RESET}\n"
yum install -y nc
-echo -e "\n>>>>>>>>> install netstat"
+printf "\n${CYAN}>>>> install netstat${RESET}\n"
yum install -y netstat
# DNS工具
-echo -e "\n>>>>>>>>> install bind-utils(dig、host、nslookup)"
+printf "\n${CYAN}>>>> install bind-utils(dig、host、nslookup)${RESET}\n"
yum install -y bind-utils
-echo -e "\n>>>>>>>>> install whois"
+printf "\n${CYAN}>>>> install whois${RESET}\n"
yum install -y whois
# 下载工具
-echo -e "\n>>>>>>>>> install curl"
+printf "\n${CYAN}>>>> install curl${RESET}\n"
yum install -y curl
-echo -e "\n>>>>>>>>> install wget"
+printf "\n${CYAN}>>>> install wget${RESET}\n"
yum install -y wget
# 编辑工具
-echo -e "\n>>>>>>>>> install emacs"
+printf "\n${CYAN}>>>> install emacs${RESET}\n"
yum install -y emacs
-echo -e "\n>>>>>>>>> install vim"
+printf "\n${CYAN}>>>> install vim${RESET}\n"
yum install -y vim
# 流量工具
-echo -e "\n>>>>>>>>> install iftop"
+printf "\n${CYAN}>>>> install iftop${RESET}\n"
yum install -y iftop
-echo -e "\n>>>>>>>>> install nethogs"
+printf "\n${CYAN}>>>> install nethogs${RESET}\n"
yum install -y nethogs
# 抓包工具
-echo -e "\n>>>>>>>>> install tcpdump"
+printf "\n${CYAN}>>>> install tcpdump${RESET}\n"
yum install -y tcpdump
# 压缩工具
-echo -e "\n>>>>>>>>> install unzip"
+printf "\n${CYAN}>>>> install unzip${RESET}\n"
yum install -y unzip
# 版本控制工具
-echo -e "\n>>>>>>>>> install git"
+printf "\n${CYAN}>>>> install git${RESET}\n"
yum install -y git
-echo -e "\n>>>>>>>>> install subversion"
+printf "\n${CYAN}>>>> install subversion${RESET}\n"
yum install -y subversion
+
+printf "\n${GREEN}<<<<<<<< 安装常用命令工具结束${RESET}\n"
diff --git a/codes/linux/sys/set-dns.sh b/codes/linux/sys/set-dns.sh
index ff3c389e..c69a7a9b 100644
--- a/codes/linux/sys/set-dns.sh
+++ b/codes/linux/sys/set-dns.sh
@@ -1,32 +1,36 @@
#!/usr/bin/env bash
+# ---------------------------------------------------------------------------------
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+# ---------------------------------------------------------------------------------
+
###################################################################################
-# 在 /etc/resolv.conf 中设置 DNS 服务器
-# 在 /etc/hosts 中设置本机域名
+# 在 /etc/resolv.conf 中配置 DNS 服务器
+# 在 /etc/hosts 中配置本机域名
# @author: Zhang Peng
###################################################################################
-ip='127.0.0.1'
-function getDeviceIp() {
- ip=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
-}
-function setDNSServer() {
-echo -e "设置DNS服务器"
+printf "\n${GREEN}>>>>>>>>> 配置 DNS 开始${RESET}\n"
+
+printf "\n${CYAN}>>>> 配置 DNS 解析服务器${RESET}\n"
cat >> /etc/resolv.conf << EOF
nameserver 114.114.114.114
nameserver 8.8.8.8
EOF
-}
-function setHosts() {
-getDeviceIp
+printf "\n${CYAN}>>>> 配置本机域名和IP映射${RESET}\n"
+ip=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
host=`hostname`
cat >> /etc/hosts << EOF
${ip} ${host}
EOF
-}
-######################################## MAIN ########################################
-echo -e "\n>>>>>>>>> 配置系统环境"
-setDNSServer
-setHosts
+printf "\n${GREEN}<<<<<<<< 配置 DNS 结束${RESET}\n"
diff --git a/codes/linux/sys/set-ntp.sh b/codes/linux/sys/set-ntp.sh
index 29945fd3..a95b2d2f 100644
--- a/codes/linux/sys/set-ntp.sh
+++ b/codes/linux/sys/set-ntp.sh
@@ -1,28 +1,42 @@
#!/usr/bin/env bash
+# ---------------------------------------------------------------------------------
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+# ---------------------------------------------------------------------------------
+
###################################################################################
# 使用 NTP 进行时间同步
# 参考:https://www.cnblogs.com/quchunhui/p/7658853.html
# @author: Zhang Peng
###################################################################################
-echo -e "\n>>>>>>>>> 设置 ntp"
+printf "\n${GREEN}>>>>>>>>> 设置 NTP 开始${RESET}\n"
-echo -e "先安装时钟同步工具 ntp"
+printf "\n${CYAN}>>>> 安装 NTP 服务${RESET}\n"
yum -y install ntp
ip=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
/sbin/iptables -A INPUT -p UDP -i eth0 -s ${ip}/24 --dport 123 -j ACCEPT
-echo -e "启动 NTP 服务"
+printf "\n${CYAN}>>>> 启动 NTP 服务${RESET}\n"
systemctl start ntpd.service
-echo -e "立即执行时间同步"
+printf "\n${CYAN}>>>> 立即执行时间同步${RESET}\n"
/usr/sbin/ntpdate ntp.sjtu.edu.cn
-echo -e "自动定时同步时间"
+printf "\n${CYAN}>>>> 自动定时同步时间${RESET}\n"
echo "* 3 * * * /usr/sbin/ntpdate ntp.sjtu.edu.cn" >> /etc/crontab
systemctl restart crond.service
-echo -e "同步后系统时间:"
+printf "\n${CYAN}>>>> 同步结束,当前系统时间:${RESET}\n"
date
+
+printf "\n${GREEN}<<<<<<<< 设置 NTP 结束${RESET}\n"
diff --git a/codes/linux/sys/stop-firewall.sh b/codes/linux/sys/stop-firewall.sh
index 09824276..7214e297 100644
--- a/codes/linux/sys/stop-firewall.sh
+++ b/codes/linux/sys/stop-firewall.sh
@@ -1,10 +1,23 @@
#!/usr/bin/env bash
+# ---------------------------------------------------------------------------------
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+# ---------------------------------------------------------------------------------
+
###################################################################################
-# 彻底关闭防火墙
+# 关闭防火墙
# 参考:https://www.cnblogs.com/moxiaoan/p/5683743.html
# @author: Zhang Peng
###################################################################################
systemctl stop firewalld
systemctl disable firewalld
+printf "\n${GREEN}<<<<<<<< 已关闭防火墙${RESET}\n"
diff --git a/codes/linux/sys/sys-settings.sh b/codes/linux/sys/sys-settings.sh
index e08c7d0f..eb93a30e 100644
--- a/codes/linux/sys/sys-settings.sh
+++ b/codes/linux/sys/sys-settings.sh
@@ -1,57 +1,69 @@
#!/usr/bin/env bash
+# ---------------------------------------------------------------------------------
+# 控制台颜色
+BLACK="\033[1;30m"
+RED="\033[1;31m"
+GREEN="\033[1;32m"
+YELLOW="\033[1;33m"
+BLUE="\033[1;34m"
+PURPLE="\033[1;35m"
+CYAN="\033[1;36m"
+RESET="$(tput sgr0)"
+# ---------------------------------------------------------------------------------
+
printHeadInfo() {
-cat << EOF
+ printf "${BLUE}\n"
+ cat << EOF
###################################################################################
# Linux Centos7 系统配置脚本(根据需要选择)
# @author: Zhang Peng
###################################################################################
-
EOF
+ printf "${RESET}\n"
}
setLimit() {
-cat >> /etc/security/limits.conf << EOF
+ cat >> /etc/security/limits.conf << EOF
* - nofile 65535
* - nproc 65535
EOF
}
setLang() {
-cat > /etc/sysconfig/i18n << EOF
+ cat > /etc/sysconfig/i18n << EOF
LANG="zh_CN.UTF-8"
EOF
}
closeShutdownShortkey() {
- echo "关闭 Ctrl+Alt+Del 快捷键防止重新启动"
- sed -i 's#exec /sbin/shutdown -r now#\#exec /sbin/shutdown -r now#' /etc/init/control-alt-delete.conf
+ printf "\n${CYAN}>>>> 关闭 Ctrl+Alt+Del 快捷键防止重新启动${RESET}\n"
+ sed -i 's#exec /sbin/shutdown -r now#\#exec /sbin/shutdown -r now#' /etc/init/control-alt-delete.conf
}
closeSelinux() {
- echo "关闭 selinux"
-
- # see http://blog.51cto.com/13570193/2093299
- sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
+ # see http://blog.51cto.com/13570193/2093299
+ printf "\n${CYAN}>>>> 关闭 selinux${RESET}\n"
+ sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
}
setBootMode() {
- # 1. 停机(记得不要把 initdefault 配置为 0,因为这样会使 Linux 不能启动)
- # 2. 单用户模式,就像 Win9X 下的安全模式
- # 3. 多用户,但是没有 NFS
- # 4. 完全多用户模式,准则的运行级
- # 5. 通常不用,在一些特殊情况下可以用它来做一些事情
- # 6. X11,即进到 X-Window 系统
- # 7. 重新启动 (记得不要把 initdefault 配置为 6,因为这样会使 Linux 不断地重新启动)
- echo "设置 Linux 启动模式"
- sed -i 's/id:5:initdefault:/id:3:initdefault:/' /etc/inittab
+ # 1. 停机(记得不要把 initdefault 配置为 0,因为这样会使 Linux 不能启动)
+ # 2. 单用户模式,就像 Win9X 下的安全模式
+ # 3. 多用户,但是没有 NFS
+ # 4. 完全多用户模式,准则的运行级
+ # 5. 通常不用,在一些特殊情况下可以用它来做一些事情
+ # 6. X11,即进到 X-Window 系统
+ # 7. 重新启动 (记得不要把 initdefault 配置为 6,因为这样会使 Linux 不断地重新启动)
+ printf "\n${CYAN}>>>> 配置 Linux 启动模式${RESET}\n"
+ sed -i 's/id:5:initdefault:/id:3:initdefault:/' /etc/inittab
}
# 配置 IPv4
-configIpv4(){
-echo "配置 ipv4"
+configIpv4() {
+ printf "\n${CYAN}>>>> 配置 IPv4${RESET}\n"
-cat >> /etc/sysctl.conf << EOF
+ cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 2
@@ -78,56 +90,54 @@ EOF
# 关闭 IPv6
closeIpv6() {
-echo "关闭 ipv6"
+ printf "\n${CYAN}>>>> 关闭 IPv6${RESET}\n"
-cat > /etc/modprobe.d/ipv6.conf << EOF
+ cat > /etc/modprobe.d/ipv6.conf << EOF
alias net-pf-10 off
options ipv6 disable=1
EOF
-echo "NETWORKING_IPV6=off" >> /etc/sysconfig/network
+ echo "NETWORKING_IPV6=off" >> /etc/sysconfig/network
}
# 入口函数
main() {
-PS3="请选择要执行的操作:"
-select ITEM in "设置 DNS" "设置 NTP" "关闭防火墙" "配置 IPv4" "关闭 IPv6" "全部执行"
-do
-
-case ${ITEM} in
- "设置 DNS")
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/set-dns.sh | bash
- ;;
- "设置 NTP")
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/set-ntp.sh | bash
- ;;
- "关闭防火墙")
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/stop-firewall.sh | bash
- ;;
- "配置 IPv4")
- configIpv4
- ;;
- "关闭 IPv6")
- closeIpv6
- ;;
- "全部执行")
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/set-dns.sh | bash
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/set-ntp.sh | bash
- curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/sys/stop-firewall.sh | bash
- configIpv4
- closeIpv6
- ;;
- *)
- echo -e "输入项不支持!"
- main
- ;;
-esac
-break
-done
+ PS3="请选择要执行的操作:"
+ select ITEM in "配置 DNS" "配置 NTP" "关闭防火墙" "配置 IPv4" "关闭 IPv6" "全部执行"
+ do
+
+ case ${ITEM} in
+ "配置 DNS")
+ sh ${root}/set-dns.sh ;;
+ "配置 NTP")
+ sh ${root}/set-ntp.sh ;;
+ "关闭防火墙")
+ sh ${root}/stop-firewall.sh ;;
+ "配置 IPv4")
+ configIpv4 ;;
+ "关闭 IPv6")
+ closeIpv6 ;;
+ "全部执行")
+ sh ${root}/set-dns.sh
+ sh ${root}/set-ntp.sh
+ sh ${root}/stop-firewall.sh
+ configIpv4
+ closeIpv6
+ ;;
+ *)
+ printf "\n${RED}输入项不支持${RESET}\n"
+ main
+ ;;
+ esac
+ break
+ done
}
######################################## MAIN ########################################
-filepath=$(cd "$(dirname "$0")"; pwd)
+root=$(pwd)
+if [[ -n $1 ]]; then
+ root=$1
+fi
printHeadInfo
main
diff --git a/codes/linux/sys/syscheck b/codes/linux/sys/syscheck
deleted file mode 100644
index 6ced5856..00000000
--- a/codes/linux/sys/syscheck
+++ /dev/null
@@ -1,325 +0,0 @@
-#!/usr/bin/env bash
-
-##############################################################################
-# console color
-C_RESET="$(tput sgr0)"
-C_BLACK="\033[1;30m"
-C_RED="\033[1;31m"
-C_GREEN="\033[1;32m"
-C_YELLOW="\033[1;33m"
-C_BLUE="\033[1;34m"
-C_PURPLE="\033[1;35m"
-C_CYAN="\033[1;36m"
-C_WHITE="\033[1;37m"
-##############################################################################
-
-printf "${C_PURPLE}"
-cat << EOF
-
-###################################################################################
-# 系统信息检查脚本
-# @author: Zhang Peng
-###################################################################################
-
-EOF
-printf "${C_RESET}"
-
-[[ $(id -u) -gt 0 ]] && echo "请用root用户执行此脚本!" && exit 1
-sysversion=$(rpm -q centos-release|cut -d- -f3)
-double_line="==============================================================="
-line="----------------------------------------------"
-
-# 打印头部信息
-printHeadInfo() {
-cat << EOF
-
-+---------------------------------------------------------------------------------+
-| 欢迎使用 【系统信息检查脚本】 |
-| @author: Zhang Peng |
-+---------------------------------------------------------------------------------+
-
-EOF
-}
-
-# 打印尾部信息
-printFootInfo() {
-cat << EOF
-
-+---------------------------------------------------------------------------------+
-| 脚本执行结束,感谢使用! |
-+---------------------------------------------------------------------------------+
-
-EOF
-}
-
-options=("获取系统信息" "获取服务信息" "获取CPU信息" "获取系统网络信息" "获取系统内存信息" "获取系统磁盘信息" "获取CPU/内存占用TOP10" "获取系统用户信息" "输出所有信息" "退出")
-printMenu() {
-printf "${C_BLUE}"
-printf "主菜单:\n"
-for i in "${!options[@]}"; do
- index=`expr ${i} + 1`
- val=`expr ${index} % 2`
- printf "\t(%02d) %-30s" "${index}" "${options[$i]}"
- if [[ ${val} -eq 0 ]]; then
- printf "\n"
- fi
-done
-printf "${C_BLUE}请输入需要执行的指令:\n"
-printf "${C_RESET}"
-}
-
-# 获取系统信息
-get_systatus_info() {
- sys_os=$(uname -o)
- sys_release=$(cat /etc/redhat-release)
- sys_kernel=$(uname -r)
- sys_hostname=$(hostname)
- sys_selinux=$(getenforce)
- sys_lang=$(echo $LANG)
- sys_lastreboot=$(who -b | awk '{print $3,$4}')
- sys_runtime=$(uptime |awk '{print $3,$4}'|cut -d, -f1)
- sys_time=$(date)
- sys_load=$(uptime |cut -d: -f5)
-
-cat << EOF
-【系统信息】
-
-系统: ${sys_os}
-发行版本: ${sys_release}
-系统内核: ${sys_kernel}
-主机名: ${sys_hostname}
-selinux状态: ${sys_selinux}
-系统语言: ${sys_lang}
-系统当前时间: ${sys_time}
-系统最后重启时间: ${sys_lastreboot}
-系统运行时间: ${sys_runtime}
-系统负载: ${sys_load}
-EOF
-}
-
-# 获取CPU信息
-get_cpu_info() {
- Physical_CPUs=$(grep "physical id" /proc/cpuinfo| sort | uniq | wc -l)
- Virt_CPUs=$(grep "processor" /proc/cpuinfo | wc -l)
- CPU_Kernels=$(grep "cores" /proc/cpuinfo|uniq| awk -F ': ' '{print $2}')
- CPU_Type=$(grep "model name" /proc/cpuinfo | awk -F ': ' '{print $2}' | sort | uniq)
- CPU_Arch=$(uname -m)
-cat << EOF
-【CPU信息】
-
-物理CPU个数:$Physical_CPUs
-逻辑CPU个数:$Virt_CPUs
-每CPU核心数:$CPU_Kernels
-CPU型号:$CPU_Type
-CPU架构:$CPU_Arch
-EOF
-}
-
-# 获取服务信息
-get_service_info() {
- port_listen=$(netstat -lntup|grep -v "Active Internet")
- kernel_config=$(sysctl -p 2>/dev/null)
- if [[ ${sysversion} -gt 6 ]];then
- service_config=$(systemctl list-unit-files --type=service --state=enabled|grep "enabled")
- run_service=$(systemctl list-units --type=service --state=running |grep ".service")
- else
- service_config=$(/sbin/chkconfig | grep -E ":on|:启用" |column -t)
- run_service=$(/sbin/service --status-all|grep -E "running")
- fi
-cat << EOF
-【服务信息】
-
-${service_config}
-${line}
-运行的服务:
-
-${run_service}
-${line}
-监听端口:
-
-${port_listen}
-${line}
-内核参考配置:
-
-${kernel_config}
-EOF
-}
-
-# 获取系统内存信息
-get_mem_info() {
- check_mem=$(free -m)
- MemTotal=$(grep MemTotal /proc/meminfo| awk '{print $2}') #KB
- MemFree=$(grep MemFree /proc/meminfo| awk '{print $2}') #KB
- let MemUsed=MemTotal-MemFree
- MemPercent=$(awk "BEGIN {if($MemTotal==0){printf 100}else{printf \"%.2f\",$MemUsed*100/$MemTotal}}")
- report_MemTotal="$((MemTotal/1024))""MB" #内存总容量(MB)
- report_MemFree="$((MemFree/1024))""MB" #内存剩余(MB)
- report_MemUsedPercent=$(free | sed -n '2p' | gawk 'x = int(( $3 / $2 ) * 100) {print x}' | sed 's/$/%/')
-
-cat << EOF
-【内存信息】
-
-内存总容量(MB): ${report_MemTotal}
-内存剩余量(MB):${report_MemFree}
-内存使用率: ${report_MemUsedPercent}
-EOF
-}
-
-# 获取系统网络信息
-get_net_info() {
- pri_ipadd=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
- pub_ipadd=$(curl ifconfig.me -s)
- gateway=$(ip route | grep default | awk '{print $3}')
- mac_info=$(ip link| egrep -v "lo"|grep link|awk '{print $2}')
- dns_config=$(egrep -v "^$|^#" /etc/resolv.conf)
- route_info=$(route -n)
-cat << EOF
-【网络信息】
-
-系统公网地址:${pub_ipadd}
-系统私网地址:${pri_ipadd}
-网关地址:${gateway}
-MAC地址:${mac_info}
-
-路由信息:
-${route_info}
-
-DNS 信息:
-${dns_config}
-EOF
-}
-
-# 获取系统磁盘信息
-get_disk_info() {
- disk_info=$(fdisk -l|grep "Disk /dev"|cut -d, -f1)
- disk_use=$(df -hTP|awk '$2!="tmpfs"{print}')
- disk_percent=$(free | sed -n '2p' | gawk 'x = int(( $3 / $2 ) * 100) {print x}' | sed 's/$/%/')
- disk_inode=$(df -hiP|awk '$1!="tmpfs"{print}')
-
-cat << EOF
-【磁盘信息】
-
-${disk_info}
-
-磁盘使用: ${disk_use}
-磁盘使用百分比: ${disk_percent}
-inode信息: ${disk_inode}
-EOF
-}
-
-# 获取系统用户信息
-get_sys_user() {
- login_user=$(awk -F: '{if ($NF=="/bin/bash") print $0}' /etc/passwd)
- ssh_config=$(egrep -v "^#|^$" /etc/ssh/sshd_config)
- sudo_config=$(egrep -v "^#|^$" /etc/sudoers |grep -v "^Defaults")
- host_config=$(egrep -v "^#|^$" /etc/hosts)
- crond_config=$(for cronuser in /var/spool/cron/* ;do ls ${cronuser} 2>/dev/null|cut -d/ -f5;egrep -v "^$|^#" ${cronuser} 2>/dev/null;echo "";done)
-cat << EOF
-【用户信息】
-
-系统登录用户:
-
-${login_user}
-${line}
-ssh 配置信息:
-
-${ssh_config}
-${line}
-sudo 配置用户:
-
-${sudo_config}
-${line}
-定时任务配置:
-
-${crond_config}
-${line}
-hosts 信息:
-
-${host_config}
-EOF
-}
-
-# 获取CPU/内存占用TOP10
-get_process_top_info() {
-
- top_title=$(top -b n1 | head -7 | tail -1)
- cpu_top10=$(top -b n1 | head -17 | tail -11)
- mem_top10=$(top -b n1 | head -17 | tail -10 | sort -k10 -r)
-
-cat << EOF
-【TOP10】
-CPU占用TOP10:
-
-${cpu_top10}
-
-内存占用TOP10:
-
-${top_title}
-${mem_top10}
-EOF
-}
-
-show_dead_process() {
- printf "僵尸进程:\n"
- ps -al | gawk '{print $2,$4}' | grep Z
-}
-
-get_all_info() {
- get_systatus_info
- echo ${double_line}
- get_service_info
- echo ${double_line}
- get_cpu_info
- echo ${double_line}
- get_net_info
- echo ${double_line}
- get_mem_info
- echo ${double_line}
- get_disk_info
- echo ${double_line}
- get_process_top_info
- echo ${double_line}
- get_sys_user
-}
-
-main() {
-while [[ 1 ]]
-do
- printMenu
- read option
- local index=$[${option} - 1]
- case ${options[${index}]} in
- "获取系统信息")
- get_systatus_info;;
- "获取服务信息")
- get_service_info ;;
- "获取CPU信息")
- get_cpu_info ;;
- "获取系统网络信息")
- get_net_info ;;
- "获取系统内存信息")
- get_mem_info ;;
- "获取系统磁盘信息")
- get_disk_info ;;
- "获取CPU/内存占用TOP10")
- get_process_top_info ;;
- "获取系统用户信息")
- get_sys_user ;;
- "输出所有信息")
- get_all_info > sys.log
- printf "${C_GREEN}信息已经输出到 sys.log 中。${C_RESET}\n\n"
- ;;
- "退出")
- exit ;;
- *)
- clear
- echo "抱歉,不支持此选项";;
- esac
-done
-}
-
-######################################## MAIN ########################################
-printHeadInfo
-main
-printFootInfo
-printf "${C_RESET}"
diff --git a/codes/linux/sys/syscheck.sh b/codes/linux/sys/syscheck.sh
new file mode 100644
index 00000000..c5ac52a6
--- /dev/null
+++ b/codes/linux/sys/syscheck.sh
@@ -0,0 +1,328 @@
+#!/usr/bin/env bash
+
+##############################################################################
+# console color
+C_RESET="$(tput sgr0)"
+C_BLACK="\033[1;30m"
+C_RED="\033[1;31m"
+C_GREEN="\033[1;32m"
+C_YELLOW="\033[1;33m"
+C_BLUE="\033[1;34m"
+C_PURPLE="\033[1;35m"
+C_CYAN="\033[1;36m"
+C_WHITE="\033[1;37m"
+##############################################################################
+
+printf "${C_PURPLE}"
+cat << EOF
+
+###################################################################################
+# 系统信息检查脚本
+# @author: Zhang Peng
+###################################################################################
+
+EOF
+printf "${C_RESET}"
+
+[[ $(id -u) -gt 0 ]] && echo "请用root用户执行此脚本!" && exit 1
+sysversion=$(rpm -q centos-release | cut -d- -f3)
+double_line="==============================================================="
+line="----------------------------------------------"
+
+# 打印头部信息
+printHeadInfo() {
+ cat << EOF
+
++---------------------------------------------------------------------------------+
+| 欢迎使用 【系统信息检查脚本】 |
+| @author: Zhang Peng |
++---------------------------------------------------------------------------------+
+
+EOF
+}
+
+# 打印尾部信息
+printFootInfo() {
+ cat << EOF
+
++---------------------------------------------------------------------------------+
+| 脚本执行结束,感谢使用! |
++---------------------------------------------------------------------------------+
+
+EOF
+}
+
+options=( "获取系统信息" "获取服务信息" "获取CPU信息" "获取系统网络信息" "获取系统内存信息" "获取系统磁盘信息" "获取CPU/内存占用TOP10" "获取系统用户信息" "输出所有信息" "退出" )
+printMenu() {
+ printf "${C_BLUE}"
+ printf "主菜单:\n"
+ for i in "${!options[@]}"; do
+ index=`expr ${i} + 1`
+ val=`expr ${index} % 2`
+ printf "\t(%02d) %-30s" "${index}" "${options[$i]}"
+ if [[ ${val} -eq 0 ]]; then
+ printf "\n"
+ fi
+ done
+ printf "${C_BLUE}请输入需要执行的指令:\n"
+ printf "${C_RESET}"
+}
+
+# 获取系统信息
+get_systatus_info() {
+ sys_os=$(uname -o)
+ sys_release=$(cat /etc/redhat-release)
+ sys_kernel=$(uname -r)
+ sys_hostname=$(hostname)
+ sys_selinux=$(getenforce)
+ sys_lang=$(echo $LANG)
+ sys_lastreboot=$(who -b | awk '{print $3,$4}')
+ sys_runtime=$(uptime | awk '{print $3,$4}' | cut -d, -f1)
+ sys_time=$(date)
+ sys_load=$(uptime | cut -d: -f5)
+
+ cat << EOF
+【系统信息】
+
+系统: ${sys_os}
+发行版本: ${sys_release}
+系统内核: ${sys_kernel}
+主机名: ${sys_hostname}
+selinux状态: ${sys_selinux}
+系统语言: ${sys_lang}
+系统当前时间: ${sys_time}
+系统最后重启时间: ${sys_lastreboot}
+系统运行时间: ${sys_runtime}
+系统负载: ${sys_load}
+EOF
+}
+
+# 获取CPU信息
+get_cpu_info() {
+ Physical_CPUs=$(grep "physical id" /proc/cpuinfo | sort | uniq | wc -l)
+ Virt_CPUs=$(grep "processor" /proc/cpuinfo | wc -l)
+ CPU_Kernels=$(grep "cores" /proc/cpuinfo | uniq | awk -F ': ' '{print $2}')
+ CPU_Type=$(grep "model name" /proc/cpuinfo | awk -F ': ' '{print $2}' | sort | uniq)
+ CPU_Arch=$(uname -m)
+ cat << EOF
+【CPU信息】
+
+物理CPU个数:$Physical_CPUs
+逻辑CPU个数:$Virt_CPUs
+每CPU核心数:$CPU_Kernels
+CPU型号:$CPU_Type
+CPU架构:$CPU_Arch
+EOF
+}
+
+# 获取服务信息
+get_service_info() {
+ port_listen=$(netstat -lntup | grep -v "Active Internet")
+ kernel_config=$(sysctl -p 2> /dev/null)
+ if [[ ${sysversion} -gt 6 ]]; then
+ service_config=$(systemctl list-unit-files --type=service --state=enabled | grep "enabled")
+ run_service=$(systemctl list-units --type=service --state=running | grep ".service")
+ else
+ service_config=$(/sbin/chkconfig | grep -E ":on|:启用" | column -t)
+ run_service=$(/sbin/service --status-all | grep -E "running")
+ fi
+ cat << EOF
+【服务信息】
+
+${service_config}
+ ${line}
+运行的服务:
+
+${run_service}
+ ${line}
+监听端口:
+
+${port_listen}
+ ${line}
+内核参考配置:
+
+${kernel_config}
+EOF
+}
+
+# 获取系统内存信息
+get_mem_info() {
+ check_mem=$(free -m)
+ MemTotal=$(grep MemTotal /proc/meminfo | awk '{print $2}') #KB
+ MemFree=$(grep MemFree /proc/meminfo | awk '{print $2}') #KB
+ let MemUsed=MemTotal-MemFree
+ MemPercent=$(awk "BEGIN {if($MemTotal==0){printf 100}else{printf \"%.2f\",$MemUsed*100/$MemTotal}}")
+ report_MemTotal="$((MemTotal/1024))" "MB" #内存总容量(MB)
+ report_MemFree="$((MemFree/1024))" "MB" #内存剩余(MB)
+ report_MemUsedPercent=$(free | sed -n '2p' | gawk 'x = int(( $3 / $2 ) * 100) {print x}' | sed 's/$/%/')
+
+ cat << EOF
+【内存信息】
+
+内存总容量(MB): ${report_MemTotal}
+内存剩余量(MB):${report_MemFree}
+内存使用率: ${report_MemUsedPercent}
+EOF
+}
+
+# 获取系统网络信息
+get_net_info() {
+ pri_ipadd=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
+ pub_ipadd=$(curl ifconfig.me -s)
+ gateway=$(ip route | grep default | awk '{print $3}')
+ mac_info=$(ip link | egrep -v "lo" | grep link | awk '{print $2}')
+ dns_config=$(egrep -v "^$|^#" /etc/resolv.conf)
+ route_info=$(route -n)
+ cat << EOF
+【网络信息】
+
+系统公网地址:${pub_ipadd}
+系统私网地址:${pri_ipadd}
+网关地址:${gateway}
+MAC地址:${mac_info}
+
+路由信息:
+${route_info}
+
+DNS 信息:
+${dns_config}
+EOF
+}
+
+# 获取系统磁盘信息
+get_disk_info() {
+ disk_info=$(fdisk -l | grep "Disk /dev" | cut -d, -f1)
+ disk_use=$(df -hTP | awk '$2!="tmpfs"{print}')
+ disk_percent=$(free | sed -n '2p' | gawk 'x = int(( $3 / $2 ) * 100) {print x}' | sed 's/$/%/')
+ disk_inode=$(df -hiP | awk '$1!="tmpfs"{print}')
+
+ cat << EOF
+【磁盘信息】
+
+${disk_info}
+
+磁盘使用: ${disk_use}
+磁盘使用百分比: ${disk_percent}
+inode信息: ${disk_inode}
+EOF
+}
+
+# 获取系统用户信息
+get_sys_user() {
+ login_user=$(awk -F: '{if ($NF=="/bin/bash") print $0}' /etc/passwd)
+ ssh_config=$(egrep -v "^#|^$" /etc/ssh/sshd_config)
+ sudo_config=$(egrep -v "^#|^$" /etc/sudoers | grep -v "^Defaults")
+ host_config=$(egrep -v "^#|^$" /etc/hosts)
+ crond_config=$(for cronuser in /var/spool/cron/*; do
+ ls ${cronuser} 2> /dev/null | cut -d/ -f5; egrep -v "^$|^#" ${cronuser} 2> /dev/null;
+ echo "";
+ done)
+ cat << EOF
+【用户信息】
+
+系统登录用户:
+
+${login_user}
+ ${line}
+ssh 配置信息:
+
+${ssh_config}
+ ${line}
+sudo 配置用户:
+
+${sudo_config}
+ ${line}
+定时任务配置:
+
+${crond_config}
+ ${line}
+hosts 信息:
+
+${host_config}
+EOF
+}
+
+# 获取CPU/内存占用TOP10
+get_process_top_info() {
+
+ top_title=$(top -b n1 | head -7 | tail -1)
+ cpu_top10=$(top -b n1 | head -17 | tail -11)
+ mem_top10=$(top -b n1 | head -17 | tail -10 | sort -k10 -r)
+
+ cat << EOF
+【TOP10】
+CPU占用TOP10:
+
+${cpu_top10}
+
+内存占用TOP10:
+
+${top_title}
+ ${mem_top10}
+EOF
+}
+
+show_dead_process() {
+ printf "僵尸进程:\n"
+ ps -al | gawk '{print $2,$4}' | grep Z
+}
+
+get_all_info() {
+ get_systatus_info
+ echo ${double_line}
+ get_service_info
+ echo ${double_line}
+ get_cpu_info
+ echo ${double_line}
+ get_net_info
+ echo ${double_line}
+ get_mem_info
+ echo ${double_line}
+ get_disk_info
+ echo ${double_line}
+ get_process_top_info
+ echo ${double_line}
+ get_sys_user
+}
+
+main() {
+ while [[ 1 ]]
+ do
+ printMenu
+ read option
+ local index=$[ ${option} - 1 ]
+ case ${options[${index}]} in
+ "获取系统信息")
+ get_systatus_info ;;
+ "获取服务信息")
+ get_service_info ;;
+ "获取CPU信息")
+ get_cpu_info ;;
+ "获取系统网络信息")
+ get_net_info ;;
+ "获取系统内存信息")
+ get_mem_info ;;
+ "获取系统磁盘信息")
+ get_disk_info ;;
+ "获取CPU/内存占用TOP10")
+ get_process_top_info ;;
+ "获取系统用户信息")
+ get_sys_user ;;
+ "输出所有信息")
+ get_all_info > sys.log
+ printf "${C_GREEN}信息已经输出到 sys.log 中。${C_RESET}\n\n"
+ ;;
+ "退出")
+ exit ;;
+ *)
+ clear
+ echo "抱歉,不支持此选项" ;;
+ esac
+ done
+}
+
+######################################## MAIN ########################################
+printHeadInfo
+main
+printFootInfo
+printf "${C_RESET}"
diff --git a/codes/linux/tool/Autoinstall_ELK_V1.3.sh b/codes/linux/tool/Autoinstall_ELK_V1.3.sh
index 4d1f583a..b673c571 100644
--- a/codes/linux/tool/Autoinstall_ELK_V1.3.sh
+++ b/codes/linux/tool/Autoinstall_ELK_V1.3.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#mail:xuel@anchnet.com
#data:2017/9/7
#AutoInstall ELK scripts
@@ -9,65 +10,66 @@ echo "# Auto Install ELK. ##"
echo "# Press Ctrl + C to cancel ##"
echo "# Any key to continue ##"
echo "##########################################"
-read -p
+read -p
software_dir="/usr/local/software"
elasticsearch_url="https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.1.tar.gz"
kibana_url="https://artifacts.elastic.co/downloads/kibana/kibana-5.4.1-linux-x86_64.tar.gz"
logstash_url="https://artifacts.elastic.co/downloads/logstash/logstash-5.4.1.tar.gz"
filebeat_url="https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-5.4.1-linux-x86_64.tar.gz"
-sys_version=`cat /etc/redhat-release |awk '{print $4}'|cut -d. -f1`
-IP=`ip addr|grep "inet "|grep -v 127.0.0.1|awk '{print $2}'|cut -d/ -f1`
+sys_version=`cat /etc/redhat-release | awk '{print $4}' | cut -d. -f1`
+IP=`ip addr | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1`
jvm_conf="/usr/local/elasticsearch/config/jvm.options"
-sys_mem=`free -m|grep Mem:|awk '{print $2}'|awk '{sum+=$1} END {print sum/1024}'|cut -d. -f1`
+sys_mem=`free -m | grep Mem: | awk '{print $2}' | awk '{sum+=$1} END {print sum/1024}' | cut -d. -f1`
#wget software
wget_fun() {
-if [ ! -d ${software_dir} ];then
- mkdir -p ${software_dir} && cd ${software_dir}
-else
- cd ${software_dir}
-fi
-for software in $elasticsearch_url $kibana_url $logstash_url $filebeat_url
-do
- wget -c $software
-done
-clear
+ if [ ! -d ${software_dir} ]; then
+ mkdir -p ${software_dir} && cd ${software_dir}
+ else
+ cd ${software_dir}
+ fi
+ for software in $elasticsearch_url $kibana_url $logstash_url $filebeat_url
+ do
+ wget -c $software
+ done
+ clear
}
+
#initial system:install java wget;set hostname;disable firewalld
init_sys() {
-[ -f /etc/init.d/functions ] && . /etc/init.d/functions
-[ "${sys_version}" != "7" ] && echo "Error:This Scripts Support Centos7.xx" && exit 1
-[ $(id -u) != "0" ] && echo "Error: You must be root to run this script" && exit 1
-sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config
-setenforce 0
-yum install -y java-1.8.0-openjdk wget net-tools
-hostnamectl set-hostname elk-server
-systemctl stop firewalld
-cat >>/etc/security/limits.conf<> /etc/security/limits.conf << EOF
+* soft nofile 65536
+* hard nofile 65536
+* soft nproc 65536
* hard nproc 65536
EOF
}
#install elasticsearch
install_elasticsearch() {
-cd $software_dir
-tar zxf elasticsearch-5.4.1.tar.gz
-mv elasticsearch-5.4.1 /usr/local/elasticsearch
-mkdir -p /usr/local/elasticsearch/data /usr/local/elasticsearch/logs
-useradd elasticsearch
-chown -R elasticsearch:elasticsearch /usr/local/elasticsearch
-echo "vm.max_map_count = 655360" >>/etc/sysctl.conf && sysctl -p
-if [ ${sys_mem} -eq 0 ];then
- sed -i "s#`grep "^-Xmx" ${jvm_conf}`#"-Xmx512m"#g" ${jvm_conf}
- sed -i "s#`grep "^-Xms" ${jvm_conf}`#"-Xms512m"#g" ${jvm_conf}
-else
- sed -i "s#`grep "^-Xmx" ${jvm_conf}`#"-Xmx${sys_mem}g"#g" ${jvm_conf}
- sed -i "s#`grep "^-Xms" ${jvm_conf}`#"-Xms${sys_mem}g"#g" ${jvm_conf}
-fi
-cat >>/usr/local/elasticsearch/config/elasticsearch.yml<> /etc/sysctl.conf && sysctl -p
+ if [ ${sys_mem} -eq 0 ]; then
+ sed -i "s#`grep "^-Xmx" ${jvm_conf}`#"-Xmx512m"#g" ${jvm_conf}
+ sed -i "s#`grep "^-Xms" ${jvm_conf}`#"-Xms512m"#g" ${jvm_conf}
+ else
+ sed -i "s#`grep "^-Xmx" ${jvm_conf}`#"-Xmx${sys_mem}g"#g" ${jvm_conf}
+ sed -i "s#`grep "^-Xms" ${jvm_conf}`#"-Xms${sys_mem}g"#g" ${jvm_conf}
+ fi
+ cat >> /usr/local/elasticsearch/config/elasticsearch.yml << EOF
cluster.name: my-application
node.name: elk-server
path.data: /usr/local/elasticsearch/data
@@ -76,15 +78,15 @@ network.host: 127.0.0.1
http.port: 9200
discovery.zen.ping.unicast.hosts: ["elk-server"]
EOF
-su - elasticsearch -c "nohup /usr/local/elasticsearch/bin/elasticsearch &"
+ su - elasticsearch -c "nohup /usr/local/elasticsearch/bin/elasticsearch &"
}
#install logstash
install_logstash() {
-cd $software_dir
-tar -zxf logstash-5.4.1.tar.gz
-mv logstash-5.4.1 /usr/local/logstash
-cat>/usr/local/logstash/config/01-syslog.conf< /usr/local/logstash/config/01-syslog.conf << EOF
input {
beats {
port => "5044"
@@ -97,15 +99,15 @@ output {
stdout { codec => rubydebug }
}
EOF
-nohup /usr/local/logstash/bin/logstash -f /usr/local/logstash/config/01-syslog.conf & >/dev/null
+ nohup /usr/local/logstash/bin/logstash -f /usr/local/logstash/config/01-syslog.conf & > /dev/null
}
#install filebeat
install_filebeat() {
-cd $software_dir
-tar -zxf filebeat-5.4.1-linux-x86_64.tar.gz
-mv filebeat-5.4.1-linux-x86_64 /usr/local/filebeat
-cat >/usr/local/filebeat/filebeat.yml< /usr/local/filebeat/filebeat.yml << EOF
filebeat.prospectors:
- input_type: log
paths:
@@ -113,52 +115,53 @@ filebeat.prospectors:
output.logstash:
hosts: ["127.0.0.1:5044"]
EOF
-cd /usr/local/filebeat/
-nohup /usr/local/filebeat/filebeat & >/dev/null
+ cd /usr/local/filebeat/
+ nohup /usr/local/filebeat/filebeat & > /dev/null
}
#install kibana
install_kibana() {
-cd $software_dir
-tar -zxf kibana-5.4.1-linux-x86_64.tar.gz
-mv kibana-5.4.1-linux-x86_64 /usr/local/kibana
-cat >> /usr/local/kibana/config/kibana.yml <> /usr/local/kibana/config/kibana.yml << EOF
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.url: "http://127.0.0.1:9200"
EOF
-nohup /usr/local/kibana/bin/kibana & >/dev/null
+ nohup /usr/local/kibana/bin/kibana & > /dev/null
}
check() {
-port=$1
-program=$2
-check_port=`netstat -lntup|grep ${port}|wc -l`
-check_program=`ps -ef|grep ${program}|grep -v grep|wc -l`
-if [ $check_port -gt 0 ] && [ $check_program -gt 0 ];then
- action "${program} run is ok!" /bin/true
-else
- action "${program} run is error!" /bin/false
-fi
+ port=$1
+ program=$2
+ check_port=`netstat -lntup | grep ${port} | wc -l`
+ check_program=`ps -ef | grep ${program} | grep -v grep | wc -l`
+ if [ $check_port -gt 0 ] && [ $check_program -gt 0 ]; then
+ action "${program} run is ok!" /bin/true
+ else
+ action "${program} run is error!" /bin/false
+ fi
}
main() {
-init_sys
-wget_fun
-install_elasticsearch
-install_filebeat
-install_logstash
-install_kibana
-echo -e "\033[32m Checking Elasticsearch...\033[0m"
-sleep 20
-check :9200 "elasticsearch"
-echo -e "\033[32m Checking Logstash...\033[0m"
-sleep 2
-check ":9600" "logstash"
-echo -e "\033[32m Checking Kibana...\033[0m"
-sleep 2
-check ":5601" "kibana"
-action "ELK install is success!" /bin/true
-echo "url:http://$IP:5601"
+ init_sys
+ wget_fun
+ install_elasticsearch
+ install_filebeat
+ install_logstash
+ install_kibana
+ echo -e "\033[32m Checking Elasticsearch...\033[0m"
+ sleep 20
+ check :9200 "elasticsearch"
+ echo -e "\033[32m Checking Logstash...\033[0m"
+ sleep 2
+ check ":9600" "logstash"
+ echo -e "\033[32m Checking Kibana...\033[0m"
+ sleep 2
+ check ":5601" "kibana"
+ action "ELK install is success!" /bin/true
+ echo "url:http://$IP:5601"
}
+
main
diff --git a/codes/linux/tool/Cpu_Limit.sh b/codes/linux/tool/Cpu_Limit.sh
index 1d959da0..2cfa6de0 100644
--- a/codes/linux/tool/Cpu_Limit.sh
+++ b/codes/linux/tool/Cpu_Limit.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# auth:kaliarch
# func:sys info check
# version:v1.0
@@ -16,7 +17,7 @@ LIMIT_CPU=85
LOG_DIR=/var/log/cpulimit/
# 超过阀值进程pid
-PIDARG=$(ps -aux |awk -v CPU=${PEC_CPU} '{if($3 > CPU) print $2}')
+PIDARG=$(ps -aux | awk -v CPU=${PEC_CPU} '{if($3 > CPU) print $2}')
CPULIMITCMD=$(which cpulimit)
install_cpulimit() {
@@ -29,25 +30,25 @@ install_cpulimit() {
do_cpulimit() {
-[ ! -d ${LOG_DIR} ] && mkdir -p ${LOG_DIR}
-for i in ${PIDARG};
-do
- MSG=$(ps -aux |awk -v pid=$i '{if($2 == pid) print $0}')
- echo ${MSG}
- [ ! -d /tmp ] && mkdir /tmp || cd /tmp
- nohup ${CPULIMITCMD} -p $i -l ${LIMIT_CPU} &
- echo "$(date) -- ${MSG}" >> ${LOG_DIR}$(date +%F).log
-done
+ [ ! -d ${LOG_DIR} ] && mkdir -p ${LOG_DIR}
+ for i in ${PIDARG};
+ do
+ MSG=$(ps -aux | awk -v pid=$i '{if($2 == pid) print $0}')
+ echo ${MSG}
+ [ ! -d /tmp ] && mkdir /tmp || cd /tmp
+ nohup ${CPULIMITCMD} -p $i -l ${LIMIT_CPU} &
+ echo "$(date) -- ${MSG}" >> ${LOG_DIR}$(date +%F).log
+ done
}
main() {
- hash cpulimit
- if [ $? -eq 0 ];then
+ hash cpulimit
+ if [ $? -eq 0 ]; then
do_cpulimit
else
install_cpulimit && do_cpulimit
- fi
+ fi
}
main
diff --git a/codes/linux/tool/Custom_Rm.sh b/codes/linux/tool/Custom_Rm.sh
index 75a06d3c..be19d78b 100644
--- a/codes/linux/tool/Custom_Rm.sh
+++ b/codes/linux/tool/Custom_Rm.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# function:自定义rm命令,每天晚上定时清理
CMD_SCRIPTS=$HOME/.rm_scripts.sh
@@ -7,7 +8,7 @@ CRON_FILE=/var/spool/cron/root
BASHRC=$HOME/.bashrc
[ ! -d ${TRASH_DIR} ] && mkdir -p ${TRASH_DIR}
-cat > $CMD_SCRIPTS < $CMD_SCRIPTS << EOF
PARA_CNT=\$#
TRASH_DIR=$TRASH_DIR
for i in \$*; do
diff --git a/codes/linux/tool/Daily_Archive.sh b/codes/linux/tool/Daily_Archive.sh
index 7e614b5e..3d2e7c4a 100644
--- a/codes/linux/tool/Daily_Archive.sh
+++ b/codes/linux/tool/Daily_Archive.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#
# Daily_Archive - Archive designated files & directories
######################################################
@@ -12,7 +13,7 @@ DATE=`date +%y%m%d`
FILE=archive$DATE.tar.gz
#
# Set Configuration and Destination File
-#
+#
CONFIG_FILE=/home/tiandi/archive/Files_To_Backup
DESTINATION=/home/tiandi/archive/$FILE
#
@@ -20,23 +21,23 @@ DESTINATION=/home/tiandi/archive/$FILE
#
# Check Backup Config file exists
#
-if [ -f $CONFIG_FILE ] #Make sure the config file still exists
+if [ -f $CONFIG_FILE ] #Make sure the config file still exists
then
- echo
+ echo
else
- echo
+ echo
echo "$CONFIG_FILE does not exist."
echo "Backup not completed due to missing Configuration file"
- echo
+ echo
exit
fi
#
# Build the names of all the files to backup
#
-FILE_NO=1 # Start on Line 1 of Config file.
-exec < $CONFIG_FILE # Redirect Std Input to name of Config File
+FILE_NO=1 # Start on Line 1 of Config file.
+exec < $CONFIG_FILE # Redirect Std Input to name of Config File
#
-read FILE_NAME # Read 1st record
+read FILE_NAME # Read 1st record
#
while [ $? -eq 0 ]
do
@@ -47,19 +48,19 @@ do
FILE_LIST="$FILE_LIST $FILE_NAME"
else
# If file doesn't exist, issue warning
- echo
+ echo
echo "$FILE_NAME, does not exist."
echo "Obviously, I will not include it in this archive."
echo "It is listed on line $FILE_NO of the config file."
echo "Continuing to build archive file."
echo
fi
-#
- FILE_NO=$[ $FILE_NO + 1 ] # Increase Line/File number by one
- read FILE_NAME # Read next record.
+ #
+ FILE_NO=$[ $FILE_NO + 1 ] # Increase Line/File number by one
+ read FILE_NAME # Read next record.
done
###########################################################
-#
+#
# Backup the files and Compress Archive
#
tar -czf $DESTINATION $FILE_LIST 2> /dev/null
diff --git a/codes/linux/tool/Hourly_Archive.sh b/codes/linux/tool/Hourly_Archive.sh
index e0396f4d..3220fcf1 100644
--- a/codes/linux/tool/Hourly_Archive.sh
+++ b/codes/linux/tool/Hourly_Archive.sh
@@ -1,10 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#
# Hourly_Archive - Every hour create an archive
######################################################
#
# Set Configuration and Destination File
-#
+#
CONFIG_FILE=/home/tiandi/archive/Files_To_Backup
#
# Gather Current Date,Month & Time
@@ -27,23 +28,23 @@ DESTINATION=$BASEDEST/$MONTH/$DAY/archive$TIME.tar.gz
#
# Check Backup Config file exists
#
-if [ -f $CONFIG_FILE ] #Make sure the config file still exists
+if [ -f $CONFIG_FILE ] #Make sure the config file still exists
then
- echo
+ echo
else
- echo
+ echo
echo "$CONFIG_FILE does not exist."
echo "Backup not completed due to missing Configuration file"
- echo
+ echo
exit
fi
#
# Build the names of all the files to backup
#
-FILE_NO=1 # Start on Line 1 of Config file.
-exec < $CONFIG_FILE # Redirect Std Input to name of Config File
+FILE_NO=1 # Start on Line 1 of Config file.
+exec < $CONFIG_FILE # Redirect Std Input to name of Config File
#
-read FILE_NAME # Read 1st record
+read FILE_NAME # Read 1st record
#
while [ $? -eq 0 ]
do
@@ -54,19 +55,19 @@ do
FILE_LIST="$FILE_LIST $FILE_NAME"
else
# If file doesn't exist, issue warning
- echo
+ echo
echo "$FILE_NAME, does not exist."
echo "Obviously, I will not include it in this archive."
echo "It is listed on line $FILE_NO of the config file."
echo "Continuing to build archive file."
echo
fi
-#
- FILE_NO=$[ $FILE_NO + 1 ] # Increase Line/File number by one
- read FILE_NAME # Read next record.
+ #
+ FILE_NO=$[ $FILE_NO + 1 ] # Increase Line/File number by one
+ read FILE_NAME # Read next record.
done
###########################################################
-#
+#
# Backup the files and Compress Archive
#
tar -czf $DESTINATION $FILE_LIST 2> /dev/null
diff --git a/codes/linux/tool/gitcheck b/codes/linux/tool/gitcheck
index c650199b..3f21766e 100644
--- a/codes/linux/tool/gitcheck
+++ b/codes/linux/tool/gitcheck
@@ -8,14 +8,14 @@
# MIT license
if [ -t 1 ]; then
- # Our output is not being redirected, so we can use colors.
- C_RED="\033[1;31m"
- C_GREEN="\033[1;32m"
- C_YELLOW="\033[1;33m"
- C_BLUE="\033[1;34m"
- C_PURPLE="\033[1;35m"
- C_CYAN="\033[1;36m"
- C_RESET="$(tput sgr0)"
+ # Our output is not being redirected, so we can use colors.
+ C_RED="\033[1;31m"
+ C_GREEN="\033[1;32m"
+ C_YELLOW="\033[1;33m"
+ C_BLUE="\033[1;34m"
+ C_PURPLE="\033[1;35m"
+ C_CYAN="\033[1;36m"
+ C_RESET="$(tput sgr0)"
fi
C_OK="$C_GREEN"
@@ -29,8 +29,8 @@ C_STASHES="$C_YELLOW"
DEBUG=0
-usage () {
- cat << EOF >&2
+usage() {
+ cat << EOF >&2
Usage: $0 [-w] [-e] [-f] [--no-X] [DIR] [DEPTH=2]
@@ -64,183 +64,185 @@ NO_UNTRACKED=0
NO_STASHES=0
while [ \! -z "$1" ]; do
- # Stop reading when we've run out of options.
- [ "$(echo "$1" | cut -c 1)" != "-" ] && break
-
- if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
- usage
- exit 1
- fi
- if [ "$1" = "-w" ]; then
- WARN_NOT_REPO=1
- fi
- if [ "$1" = "-e" ]; then
- EXCLUDE_OK=1
- fi
- if [ "$1" = "-f" ]; then
- DO_FETCH=1
- fi
- if [ "$1" = "--no-push" ]; then
- NO_PUSH=1
- fi
- if [ "$1" = "--no-pull" ]; then
- NO_PULL=1
- fi
- if [ "$1" = "--no-upstream" ]; then
- NO_UPSTREAM=1
- fi
- if [ "$1" = "--no-uncommitted" ]; then
- NO_UNCOMMITTED=1
- fi
- if [ "$1" = "--no-untracked" ]; then
- NO_UNTRACKED=1
- fi
- if [ "$1" = "--no-stashes" ]; then
- NO_STASHES=1
- fi
-
- shift
+ # Stop reading when we've run out of options.
+ [ "$(echo "$1" | cut -c 1)" != "-" ] && break
+
+ if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
+ usage
+ exit 1
+ fi
+ if [ "$1" = "-w" ]; then
+ WARN_NOT_REPO=1
+ fi
+ if [ "$1" = "-e" ]; then
+ EXCLUDE_OK=1
+ fi
+ if [ "$1" = "-f" ]; then
+ DO_FETCH=1
+ fi
+ if [ "$1" = "--no-push" ]; then
+ NO_PUSH=1
+ fi
+ if [ "$1" = "--no-pull" ]; then
+ NO_PULL=1
+ fi
+ if [ "$1" = "--no-upstream" ]; then
+ NO_UPSTREAM=1
+ fi
+ if [ "$1" = "--no-uncommitted" ]; then
+ NO_UNCOMMITTED=1
+ fi
+ if [ "$1" = "--no-untracked" ]; then
+ NO_UNTRACKED=1
+ fi
+ if [ "$1" = "--no-stashes" ]; then
+ NO_STASHES=1
+ fi
+
+ shift
done
if [ -z "$1" ]; then
- ROOT_DIR="."
+ ROOT_DIR="."
else
- ROOT_DIR="$1"
+ ROOT_DIR="$1"
fi
if [ -z "$2" ]; then
- DEPTH=2
+ DEPTH=2
else
- DEPTH="$2"
+ DEPTH="$2"
fi
# Find all .git dirs, up to DEPTH levels deep
find -L "$ROOT_DIR" -maxdepth "$DEPTH" -type d | while read -r PROJ_DIR
do
- GIT_DIR="$PROJ_DIR/.git"
-
- # If this dir is not a repo, and WARN_NOT_REPO is 1, tell the user.
- if [ \! -d "$GIT_DIR" ]; then
- if [ "$WARN_NOT_REPO" -eq 1 ] && [ "$PROJ_DIR" != "." ]; then
- printf "${PROJ_DIR}: not a git repo\n"
- fi
- continue
- fi
-
- [ $DEBUG -eq 1 ] && echo "${PROJ_DIR}"
-
- # Check if repo is locked
- if [ -f "$GIT_DIR/index.lock" ]; then
- printf "${PROJ_DIR}: ${C_LOCKED}Locked. Skipping.${C_RESET}\n"
- continue
- fi
-
- # Do a 'git fetch' if requested
- if [ "$DO_FETCH" -eq 1 ]; then
- git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" fetch -q >/dev/null
- fi
-
- # Refresh the index, or we might get wrong results.
- git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" update-index -q --refresh >/dev/null 2>&1
-
- # Find all remote branches that have been checked out and figure out if
- # they need a push or pull. We do this with various tests and put the name
- # of the branches in NEEDS_XXXX, seperated by newlines. After we're done,
- # we remove duplicates from NEEDS_XXX.
- NEEDS_PUSH_BRANCHES=""
- NEEDS_PULL_BRANCHES=""
- NEEDS_UPSTREAM_BRANCHES=""
-
- for REF_HEAD in $(cd "$GIT_DIR/refs/heads" && find . -type 'f' | sed "s/^\.\///"); do
- # Check if this branch is tracking an upstream (local/remote branch)
- UPSTREAM=$(git --git-dir "$GIT_DIR" rev-parse --abbrev-ref --symbolic-full-name "$REF_HEAD@{u}" 2>/dev/null)
- EXIT_CODE="$?"
- if [ "$EXIT_CODE" -eq 0 ]; then
- # Branch is tracking a remote branch. Find out how much behind /
- # ahead it is of that remote branch.
- CNT_AHEAD_BEHIND=$(git --git-dir "$GIT_DIR" rev-list --left-right --count "$REF_HEAD...$UPSTREAM")
- CNT_AHEAD=$(echo "$CNT_AHEAD_BEHIND" | awk '{ print $1 }')
- CNT_BEHIND=$(echo "$CNT_AHEAD_BEHIND" | awk '{ print $2 }')
-
- [ $DEBUG -eq 1 ] && echo "CNT_AHEAD_BEHIND: $CNT_AHEAD_BEHIND"
- [ $DEBUG -eq 1 ] && echo "CNT_AHEAD: $CNT_AHEAD"
- [ $DEBUG -eq 1 ] && echo "CNT_BEHIND: $CNT_BEHIND"
-
- if [ "$CNT_AHEAD" -gt 0 ]; then
- NEEDS_PUSH_BRANCHES="${NEEDS_PUSH_BRANCHES}\n$REF_HEAD"
- fi
- if [ "$CNT_BEHIND" -gt 0 ]; then
- NEEDS_PULL_BRANCHES="${NEEDS_PULL_BRANCHES}\n$REF_HEAD"
- fi
-
- # Check if this branch is a branch off another branch. and if it needs
- # to be updated.
- REV_LOCAL=$(git --git-dir "$GIT_DIR" rev-parse --verify "$REF_HEAD" 2>/dev/null)
- REV_REMOTE=$(git --git-dir "$GIT_DIR" rev-parse --verify "$UPSTREAM" 2>/dev/null)
- REV_BASE=$(git --git-dir "$GIT_DIR" merge-base "$REF_HEAD" "$UPSTREAM" 2>/dev/null)
-
- [ $DEBUG -eq 1 ] && echo "REV_LOCAL: $REV_LOCAL"
- [ $DEBUG -eq 1 ] && echo "REV_REMOTE: $REV_REMOTE"
- [ $DEBUG -eq 1 ] && echo "REV_BASE: $REV_BASE"
-
- if [ "$REV_LOCAL" = "$REV_REMOTE" ]; then
- : # NOOP
- else
- if [ "$REV_LOCAL" = "$REV_BASE" ]; then
- NEEDS_PULL_BRANCHES="${NEEDS_PULL_BRANCHES}\n$REF_HEAD"
- fi
- if [ "$REV_REMOTE" = "$REV_BASE" ]; then
- NEEDS_PUSH_BRANCHES="${NEEDS_PUSH_BRANCHES}\n$REF_HEAD"
- fi
- fi
- else
- # Branch does not have an upstream (local/remote branch).
- NEEDS_UPSTREAM_BRANCHES="${NEEDS_UPSTREAM_BRANCHES}\n$REF_HEAD"
- fi
-
- done
-
- # Remove duplicates from NEEDS_XXXX and make comma-seperated
- NEEDS_PUSH_BRANCHES=$(printf "$NEEDS_PUSH_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/")
- NEEDS_PULL_BRANCHES=$(printf "$NEEDS_PULL_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/")
- NEEDS_UPSTREAM_BRANCHES=$(printf "$NEEDS_UPSTREAM_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/")
-
- # Find out if there are unstaged, uncommitted or untracked changes
- UNSTAGED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" diff-index --quiet HEAD -- 2>/dev/null; echo $?)
- UNCOMMITTED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" diff-files --quiet --ignore-submodules --; echo $?)
- UNTRACKED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" ls-files --exclude-standard --others)
- cd "$(dirname "$GIT_DIR")" || exit
- STASHES=$(git stash list | wc -l)
- cd "$OLDPWD" || exit
-
- # Build up the status string
- IS_OK=0 # 0 = Repo needs something, 1 = Repo needs nothing ('ok')
- STATUS_NEEDS=""
- if [ \! -z "$NEEDS_PUSH_BRANCHES" ] && [ "$NO_PUSH" -eq 0 ]; then
- STATUS_NEEDS="${STATUS_NEEDS}${C_NEEDS_PUSH}Needs push ($NEEDS_PUSH_BRANCHES)${C_RESET} "
- fi
- if [ \! -z "$NEEDS_PULL_BRANCHES" ] && [ "$NO_PULL" -eq 0 ]; then
- STATUS_NEEDS="${STATUS_NEEDS}${C_NEEDS_PULL}Needs pull ($NEEDS_PULL_BRANCHES)${C_RESET} "
- fi
- if [ \! -z "$NEEDS_UPSTREAM_BRANCHES" ] && [ "$NO_UPSTREAM" -eq 0 ]; then
- STATUS_NEEDS="${STATUS_NEEDS}${C_NEEDS_UPSTREAM}Needs upstream ($NEEDS_UPSTREAM_BRANCHES)${C_RESET} "
- fi
- if [ "$UNSTAGED" -ne 0 ] || [ "$UNCOMMITTED" -ne 0 ] && [ "$NO_UNCOMMITTED" -eq 0 ]; then
- STATUS_NEEDS="${STATUS_NEEDS}${C_NEEDS_COMMIT}Uncommitted changes${C_RESET} "
- fi
- if [ "$UNTRACKED" != "" ] && [ "$NO_UNTRACKED" -eq 0 ]; then
- STATUS_NEEDS="${STATUS_NEEDS}${C_UNTRACKED}Untracked files${C_RESET} "
- fi
- if [ "$STASHES" -ne 0 ] && [ "$NO_STASHES" -eq 0 ]; then
- STATUS_NEEDS="${STATUS_NEEDS}${C_STASHES}$STASHES stashes${C_RESET} "
- fi
- if [ "$STATUS_NEEDS" = "" ]; then
- IS_OK=1
- STATUS_NEEDS="${STATUS_NEEDS}${C_OK}ok${C_RESET} "
- fi
-
- # Print the output, unless repo is 'ok' and -e was specified
- if [ "$IS_OK" -ne 1 ] || [ "$EXCLUDE_OK" -ne 1 ]; then
- printf "${PROJ_DIR}: $STATUS_NEEDS\n"
- fi
+ GIT_DIR="$PROJ_DIR/.git"
+
+ # If this dir is not a repo, and WARN_NOT_REPO is 1, tell the user.
+ if [ \! -d "$GIT_DIR" ]; then
+ if [ "$WARN_NOT_REPO" -eq 1 ] && [ "$PROJ_DIR" != "." ]; then
+ printf "${PROJ_DIR}: not a git repo\n"
+ fi
+ continue
+ fi
+
+ [ $DEBUG -eq 1 ] && echo "${PROJ_DIR}"
+
+ # Check if repo is locked
+ if [ -f "$GIT_DIR/index.lock" ]; then
+ printf "${PROJ_DIR}: ${C_LOCKED}Locked. Skipping.${C_RESET}\n"
+ continue
+ fi
+
+ # Do a 'git fetch' if requested
+ if [ "$DO_FETCH" -eq 1 ]; then
+ git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" fetch -q > /dev/null
+ fi
+
+ # Refresh the index, or we might get wrong results.
+ git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" update-index -q --refresh > /dev/null 2>&1
+
+ # Find all remote branches that have been checked out and figure out if
+ # they need a push or pull. We do this with various tests and put the name
+ # of the branches in NEEDS_XXXX, seperated by newlines. After we're done,
+ # we remove duplicates from NEEDS_XXX.
+ NEEDS_PUSH_BRANCHES=""
+ NEEDS_PULL_BRANCHES=""
+ NEEDS_UPSTREAM_BRANCHES=""
+
+ for REF_HEAD in $(cd "$GIT_DIR/refs/heads" && find . -type 'f' | sed "s/^\.\///"); do
+ # Check if this branch is tracking an upstream (local/remote branch)
+ UPSTREAM=$(git --git-dir "$GIT_DIR" rev-parse --abbrev-ref --symbolic-full-name "$REF_HEAD@{u}" 2> /dev/null)
+ EXIT_CODE="$?"
+ if [ "$EXIT_CODE" -eq 0 ]; then
+ # Branch is tracking a remote branch. Find out how much behind /
+ # ahead it is of that remote branch.
+ CNT_AHEAD_BEHIND=$(git --git-dir "$GIT_DIR" rev-list --left-right --count "$REF_HEAD...$UPSTREAM")
+ CNT_AHEAD=$(echo "$CNT_AHEAD_BEHIND" | awk '{ print $1 }')
+ CNT_BEHIND=$(echo "$CNT_AHEAD_BEHIND" | awk '{ print $2 }')
+
+ [ $DEBUG -eq 1 ] && echo "CNT_AHEAD_BEHIND: $CNT_AHEAD_BEHIND"
+ [ $DEBUG -eq 1 ] && echo "CNT_AHEAD: $CNT_AHEAD"
+ [ $DEBUG -eq 1 ] && echo "CNT_BEHIND: $CNT_BEHIND"
+
+ if [ "$CNT_AHEAD" -gt 0 ]; then
+ NEEDS_PUSH_BRANCHES="${NEEDS_PUSH_BRANCHES}\n$REF_HEAD"
+ fi
+ if [ "$CNT_BEHIND" -gt 0 ]; then
+ NEEDS_PULL_BRANCHES="${NEEDS_PULL_BRANCHES}\n$REF_HEAD"
+ fi
+
+ # Check if this branch is a branch off another branch. and if it needs
+ # to be updated.
+ REV_LOCAL=$(git --git-dir "$GIT_DIR" rev-parse --verify "$REF_HEAD" 2> /dev/null)
+ REV_REMOTE=$(git --git-dir "$GIT_DIR" rev-parse --verify "$UPSTREAM" 2> /dev/null)
+ REV_BASE=$(git --git-dir "$GIT_DIR" merge-base "$REF_HEAD" "$UPSTREAM" 2> /dev/null)
+
+ [ $DEBUG -eq 1 ] && echo "REV_LOCAL: $REV_LOCAL"
+ [ $DEBUG -eq 1 ] && echo "REV_REMOTE: $REV_REMOTE"
+ [ $DEBUG -eq 1 ] && echo "REV_BASE: $REV_BASE"
+
+ if [ "$REV_LOCAL" = "$REV_REMOTE" ]; then
+ : # NOOP
+ else
+ if [ "$REV_LOCAL" = "$REV_BASE" ]; then
+ NEEDS_PULL_BRANCHES="${NEEDS_PULL_BRANCHES}\n$REF_HEAD"
+ fi
+ if [ "$REV_REMOTE" = "$REV_BASE" ]; then
+ NEEDS_PUSH_BRANCHES="${NEEDS_PUSH_BRANCHES}\n$REF_HEAD"
+ fi
+ fi
+ else
+ # Branch does not have an upstream (local/remote branch).
+ NEEDS_UPSTREAM_BRANCHES="${NEEDS_UPSTREAM_BRANCHES}\n$REF_HEAD"
+ fi
+
+ done
+
+ # Remove duplicates from NEEDS_XXXX and make comma-seperated
+ NEEDS_PUSH_BRANCHES=$(printf "$NEEDS_PUSH_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/")
+ NEEDS_PULL_BRANCHES=$(printf "$NEEDS_PULL_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/")
+ NEEDS_UPSTREAM_BRANCHES=$(printf "$NEEDS_UPSTREAM_BRANCHES" | sort | uniq | tr '\n' ',' | sed "s/^,\(.*\),$/\1/")
+
+ # Find out if there are unstaged, uncommitted or untracked changes
+ UNSTAGED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" diff-index --quiet HEAD -- 2> /dev/null;
+ echo $?)
+ UNCOMMITTED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" diff-files --quiet --ignore-submodules --;
+ echo $?)
+ UNTRACKED=$(git --work-tree "$(dirname "$GIT_DIR")" --git-dir "$GIT_DIR" ls-files --exclude-standard --others)
+ cd "$(dirname "$GIT_DIR")" || exit
+ STASHES=$(git stash list | wc -l)
+ cd "$OLDPWD" || exit
+
+ # Build up the status string
+ IS_OK=0 # 0 = Repo needs something, 1 = Repo needs nothing ('ok')
+ STATUS_NEEDS=""
+ if [ \! -z "$NEEDS_PUSH_BRANCHES" ] && [ "$NO_PUSH" -eq 0 ]; then
+ STATUS_NEEDS="${STATUS_NEEDS}${C_NEEDS_PUSH}Needs push ($NEEDS_PUSH_BRANCHES)${C_RESET} "
+ fi
+ if [ \! -z "$NEEDS_PULL_BRANCHES" ] && [ "$NO_PULL" -eq 0 ]; then
+ STATUS_NEEDS="${STATUS_NEEDS}${C_NEEDS_PULL}Needs pull ($NEEDS_PULL_BRANCHES)${C_RESET} "
+ fi
+ if [ \! -z "$NEEDS_UPSTREAM_BRANCHES" ] && [ "$NO_UPSTREAM" -eq 0 ]; then
+ STATUS_NEEDS="${STATUS_NEEDS}${C_NEEDS_UPSTREAM}Needs upstream ($NEEDS_UPSTREAM_BRANCHES)${C_RESET} "
+ fi
+ if [ "$UNSTAGED" -ne 0 ] || [ "$UNCOMMITTED" -ne 0 ] && [ "$NO_UNCOMMITTED" -eq 0 ]; then
+ STATUS_NEEDS="${STATUS_NEEDS}${C_NEEDS_COMMIT}Uncommitted changes${C_RESET} "
+ fi
+ if [ "$UNTRACKED" != "" ] && [ "$NO_UNTRACKED" -eq 0 ]; then
+ STATUS_NEEDS="${STATUS_NEEDS}${C_UNTRACKED}Untracked files${C_RESET} "
+ fi
+ if [ "$STASHES" -ne 0 ] && [ "$NO_STASHES" -eq 0 ]; then
+ STATUS_NEEDS="${STATUS_NEEDS}${C_STASHES}$STASHES stashes${C_RESET} "
+ fi
+ if [ "$STATUS_NEEDS" = "" ]; then
+ IS_OK=1
+ STATUS_NEEDS="${STATUS_NEEDS}${C_OK}ok${C_RESET} "
+ fi
+
+ # Print the output, unless repo is 'ok' and -e was specified
+ if [ "$IS_OK" -ne 1 ] || [ "$EXCLUDE_OK" -ne 1 ]; then
+ printf "${PROJ_DIR}: $STATUS_NEEDS\n"
+ fi
done
diff --git "a/codes/linux/tool/\345\210\240\351\231\244\347\224\250\346\210\267\350\204\232\346\234\254.sh" "b/codes/linux/tool/\345\210\240\351\231\244\347\224\250\346\210\267\350\204\232\346\234\254.sh"
index 724dfc0d..a7db9303 100644
--- "a/codes/linux/tool/\345\210\240\351\231\244\347\224\250\346\210\267\350\204\232\346\234\254.sh"
+++ "b/codes/linux/tool/\345\210\240\351\231\244\347\224\250\346\210\267\350\204\232\346\234\254.sh"
@@ -1,85 +1,92 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#
# Delete_User - Automates the 4 steps to remove an account
#
#################################################################
-#
+#
# Define Functions
#
#################################################################
function get_answer {
-#
+ #
unset ANSWER
ASK_COUNT=0
-#
+ #
while [ -z "$ANSWER" ] # while no answer is given, keep asking
do
ASK_COUNT=$[ $ASK_COUNT + 1 ]
-#
- case $ASK_COUNT in # If user gives no answer in time allowed
- 2)
- echo
- echo "Please answer the question."
- echo
- ;;
- 3)
- echo
- echo "One last try... please answer the question."
- echo
- ;;
- 4)
- echo
- echo "Since you refuse to answer the question..."
- echo "exiting program."
- echo
- #
- exit
- ;;
+ #
+ case $ASK_COUNT in
+ # If user gives no answer in time allowed
+ 2)
+ echo
+ echo "Please answer the question."
+ echo
+ ;;
+ 3)
+ echo
+ echo "One last try... please answer the question."
+ echo
+ ;;
+ 4)
+ echo
+ echo "Since you refuse to answer the question..."
+ echo "exiting program."
+ echo
+ #
+ exit
+ ;;
esac
-#
+ #
echo
-#
+ #
if [ -n "$LINE2" ]
then
- echo $LINE1 # Print 2 lines
+ echo $LINE1 # Print 2 lines
echo -e $LINE2" \c"
- else # Print 1 line
+ else
+ # Print 1 line
echo -e $LINE1" \c"
fi
-#
-# Allow 60 seconds to answer before time-out
+ #
+ # Allow 60 seconds to answer before time-out
read -t 60 ANSWER
done
-#
-# Do a little variable clean-up
-#
+ #
+ # Do a little variable clean-up
+ #
unset LINE1
unset LINE2
-#
-} #end of get_answer function
+ #
+}
+
+#end of get_answer function
#
#################################################################
function process_answer {
-#
+ #
case $ANSWER in
- y|Y|YES|yes|yEs|yeS|YEs|yES)
- # If user answers "yes".do nothing.
- ;;
- *)
- # If user answers anything but "yes", exit script
- echo
- echo $EXIT_LINE1
- echo $EXIT_LINE2
- echo
- exit
- ;;
+ y | Y | YES | yes | yEs | yeS | YEs | yES)
+ # If user answers "yes".do nothing.
+ ;;
+ *)
+ # If user answers anything but "yes", exit script
+ echo
+ echo $EXIT_LINE1
+ echo $EXIT_LINE2
+ echo
+ exit
+ ;;
esac
#
# Do a little variable clean-up
unset EXIT_LINE1
unset EXIT_LINE2
-#
-} #End of process_answer function
+ #
+}
+
+#End of process_answer function
#
################################################################
#
@@ -108,9 +115,9 @@ get_answer
#
USER_ACCOUNT_RECORD=$(cat /etc/passwd | grep -w $USER_ACCOUNT)
#
-if [ $? -eq 1 ] # If the account is not found, exit script
+if [ $? -eq 1 ] # If the account is not found, exit script
then
- echo
+ echo
echo "Account, $USER_ACCOUNT, not found."
echo "Leaving the script..."
echo
@@ -143,59 +150,59 @@ echo
echo "$USER_ACCOUNT has the following processes running: "
echo
#
-ps -u $USER_ACCOUNT #List the processes running
+ps -u $USER_ACCOUNT #List the processes running
#
case $? in
-1) # No processes running for this User Account
+ 1) # No processes running for this User Account
#
- echo "There are no processes for this account currently running."
- echo
-;;
-0) # Processes running for this User Account.
+ echo "There are no processes for this account currently running."
+ echo
+ ;;
+ 0) # Processes running for this User Account.
# Ask Script User if wants us to kill the processes.
#
- unset ANSWER # I think this line is not needed
- LINE1="Would you like me to kill the process(es)? [y/n]:"
- get_answer
- #
- case $ANSWER in
- y|Y|YES|yes|Yes|yEs|yeS|YEs|yES) # if user answer "yes",
- #kill User Account processes
+ unset ANSWER # I think this line is not needed
+ LINE1="Would you like me to kill the process(es)? [y/n]:"
+ get_answer
#
- echo
- #
- # Clean-up temp file upon signals
- #
- trap "rm $USER_ACCOUNT_Running_Process.rpt" SIGTERM SIGINT SIGQUIT
- #
- # List user processes running
- ps -u $USER_ACCOUNT > $USER_ACCOUNT_Running_Process.rpt
- #
- exec < $USER_ACCOUNT_Running_Process.rpt # Make report Std Input
- #
- read USER_PROCESS_REC # First record will be blank
- read USER_PROCESS_REC
- #
- while [ $? -eq 0 ]
- do
- # obtain PID
- USER_PID=$(echo $USER_PROCESS_REC | cut -d " " -f1 )
- kill -9 $USER_PID
- echo "Killed process $USER_PID"
- read USER_PROCESS_REC
- done
- #
- echo
- #
- rm $USER_ACCOUNT_Running_Process.rpt # Remove temp report
- ;;
- *) # If user answers anything but "yes", do not kill.
- echo
- echo "Will not kill the process(es)."
- echo
+ case $ANSWER in
+ y | Y | YES | yes | Yes | yEs | yeS | YEs | yES) # if user answer "yes",
+ #kill User Account processes
+ #
+ echo
+ #
+ # Clean-up temp file upon signals
+ #
+ trap "rm$USER_ACCOUNT_Running_Process.rpt" SIGTERM SIGINT SIGQUIT
+ #
+ # List user processes running
+ ps -u $USER_ACCOUNT > $USER_ACCOUNT_Running_Process.rpt
+ #
+ exec < $USER_ACCOUNT_Running_Process.rpt # Make report Std Input
+ #
+ read USER_PROCESS_REC # First record will be blank
+ read USER_PROCESS_REC
+ #
+ while [ $? -eq 0 ]
+ do
+ # obtain PID
+ USER_PID=$(echo $USER_PROCESS_REC | cut -d " " -f1)
+ kill -9 $USER_PID
+ echo "Killed process $USER_PID"
+ read USER_PROCESS_REC
+ done
+ #
+ echo
+ #
+ rm $USER_ACCOUNT_Running_Process.rpt # Remove temp report
+ ;;
+ *) # If user answers anything but "yes", do not kill.
+ echo
+ echo "Will not kill the process(es)."
+ echo
+ ;;
+ esac
;;
- esac
-;;
esac
###################################################################################
#
@@ -216,7 +223,7 @@ echo "Please wait. This may take a while..."
REPORT_DATE=`date +%y%m%d`
REPORT_FILE=$USER_ACCOUNT"_Files_"$REPORT_DATE".rpt"
#
-find / -user $USER_ACCOUNT > $REPORT_FILE 2>/dev/null
+find / -user $USER_ACCOUNT > $REPORT_FILE 2> /dev/null
#
echo
echo "Report is complete."
@@ -240,7 +247,7 @@ EXIT_LINE1="Since you do not wish to remove the user account."
EXIT_LINE2="$USER_ACCOUNT at this time, exiting the script..."
process_answer
#
-userdel $USER_ACCOUNT # delete user account
+userdel $USER_ACCOUNT # delete user account
echo
echo "User account, $USER_ACCOUNT, has been removed"
echo
diff --git "a/codes/linux/tool/\346\237\245\347\234\213\346\214\207\345\256\232\347\233\256\345\275\225\347\243\201\347\233\230\344\275\277\347\224\250\346\203\205\345\206\265.sh" "b/codes/linux/tool/\346\237\245\347\234\213\346\214\207\345\256\232\347\233\256\345\275\225\347\243\201\347\233\230\344\275\277\347\224\250\346\203\205\345\206\265.sh"
index 4639c449..64db7315 100644
--- "a/codes/linux/tool/\346\237\245\347\234\213\346\214\207\345\256\232\347\233\256\345\275\225\347\243\201\347\233\230\344\275\277\347\224\250\346\203\205\345\206\265.sh"
+++ "b/codes/linux/tool/\346\237\245\347\234\213\346\214\207\345\256\232\347\233\256\345\275\225\347\243\201\347\233\230\344\275\277\347\224\250\346\203\205\345\206\265.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#DIRS="/var/log /home /opt"
@@ -11,9 +11,9 @@ for DIR in ${DIRS}
do
echo ""
echo "The ${DIR} Directory:"
- du -S ${DIR} 2>/dev/null |
+ du -S ${DIR} 2> /dev/null |
sort -rn |
sed '{11,$D; =}' |
- sed 'N; s/\n/ /' |
+ sed 'N; s/\n/ /' |
gawk '{printf $1 ":" "\t" $2 "\t" $3 "\n"}'
done
diff --git a/codes/shell/README.md b/codes/shell/README.md
new file mode 100644
index 00000000..0d5b2063
--- /dev/null
+++ b/codes/shell/README.md
@@ -0,0 +1,12 @@
+# Shell 脚本大全
+
+> **Shell 脚本大全** 精心收集、整理了 Linux 环境下的常见 Shell 脚本操作片段。
+>
+> 当您面临以下问题时,**Shell 脚本大全** 也许可以给你一些借鉴:
+>
+> - 你想要执行某个操作,却不知 Shell 命令如何写
+> - 你想要快速掌握 Shell 基本用法
+
+## 参考资料
+
+- [pure-bash-bible](https://github.com/dylanaraps/pure-bash-bible#change-a-string-to-lowercase)
diff --git a/codes/shell/action/README.md b/codes/shell/action/README.md
deleted file mode 100644
index 56076832..00000000
--- a/codes/shell/action/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Shell 脚本实战
-
-> 本目录的代码是本人在学习、开发中总结的一些面向实战的 Shell 代码。
diff --git a/codes/shell/action/system/dir.sh b/codes/shell/action/system/dir.sh
deleted file mode 100644
index b9499d03..00000000
--- a/codes/shell/action/system/dir.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-current_dir=$(cd `dirname $0`; pwd)
-echo "当前目录是:${current_dir}"
-
-parent_dir=$(dirname $(pwd))
-echo "父目录是:${parent_dir}"
diff --git a/codes/shell/demos/README.md b/codes/shell/demos/README.md
deleted file mode 100644
index 7f6702e6..00000000
--- a/codes/shell/demos/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Shell 示例源码
-
-> 本目录的代码是和 『[一篇文章让你彻底掌握 shell 语言](https://github.com/dunwu/linux-tutorial/blob/master/docs/linux/scripts/shell.md)』 相配套的示例代码。
diff --git a/codes/shell/demos/array-demo.sh b/codes/shell/demos/array-demo.sh
deleted file mode 100644
index 65ff2ef7..00000000
--- a/codes/shell/demos/array-demo.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env bash
-
-# 创建数组
-nums=([2]=2 [0]=0 [1]=1)
-colors=(red yellow "dark blue")
-
-# 访问数组的单个元素
-echo ${nums[1]}
-# Output: 1
-
-# 访问数组的所有元素
-echo ${colors[*]}
-# Output: red yellow dark blue
-
-echo ${colors[@]}
-# Output: red yellow dark blue
-
-printf "+ %s\n" ${colors[*]}
-# Output:
-# + red
-# + yellow
-# + dark
-# + blue
-
-printf "+ %s\n" "${colors[*]}"
-# Output:
-# + red yellow dark blue
-
-printf "+ %s\n" "${colors[@]}"
-# Output:
-# + red
-# + yellow
-# + dark blue
-
-# 访问数组的部分元素
-echo ${nums[@]:0:2}
-# Output:
-# 0 1
-
-# 访问数组长度
-echo ${#nums[*]}
-# Output:
-# 3
-
-# 向数组中添加元素
-colors=(white "${colors[@]}" green black)
-echo ${colors[@]}
-# Output:
-# white red yellow dark blue green black
-
-# 从数组中删除元素
-unset nums[0]
-echo ${nums[@]}
-# Output:
-# 1 2
diff --git a/codes/shell/demos/function/function-demo.sh b/codes/shell/demos/function/function-demo.sh
deleted file mode 100644
index 7db68a76..00000000
--- a/codes/shell/demos/function/function-demo.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-
-calc(){
- PS3="choose the oper: "
- select oper in + - \* / # 生成操作符选择菜单
- do
- echo -n "enter first num: " && read x # 读取输入参数
- echo -n "enter second num: " && read y # 读取输入参数
- exec
- case ${oper} in
- "+")
- return $((${x} + ${y}))
- ;;
- "-")
- return $((${x} - ${y}))
- ;;
- "*")
- return $((${x} * ${y}))
- ;;
- "/")
- return $((${x} / ${y}))
- ;;
- *)
- echo "${oper} is not support!"
- return 0
- ;;
- esac
- break
- done
-}
-calc
-echo "the result is: $?" # $? 获取 calc 函数返回值
-# $ ./function-demo.sh
-# 1) +
-# 2) -
-# 3) *
-# 4) /
-# choose the oper: 3
-# enter first num: 10
-# enter second num: 10
-# the result is: 100
diff --git a/codes/shell/demos/function/function-demo2.sh b/codes/shell/demos/function/function-demo2.sh
deleted file mode 100644
index 02481163..00000000
--- a/codes/shell/demos/function/function-demo2.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env bash
-
-x=0
-if [[ -n $1 ]]; then
- echo "第一个参数为:$1"
- x=$1
-else
- echo "第一个参数为空"
-fi
-
-y=0
-if [[ -n $2 ]]; then
- echo "第二个参数为:$2"
- y=$2
-else
- echo "第二个参数为空"
-fi
-
-paramsFunction(){
- echo "函数第一个入参:$1"
- echo "函数第二个入参:$2"
-}
-paramsFunction ${x} ${y}
diff --git a/codes/shell/demos/helloworld.sh b/codes/shell/demos/helloworld.sh
deleted file mode 100644
index 2b70e2c4..00000000
--- a/codes/shell/demos/helloworld.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-echo "Hello, world!"
diff --git a/codes/shell/demos/statement/break-demo.sh b/codes/shell/demos/statement/break-demo.sh
deleted file mode 100644
index eba7c164..00000000
--- a/codes/shell/demos/statement/break-demo.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-# 查找 10 以内第一个能整除 2 和 3 的正整数
-i=1
-while [[ ${i} -lt 10 ]]; do
- if [[ $((i % 3)) -eq 0 ]] && [[ $((i % 2)) -eq 0 ]]; then
- echo ${i}
- break;
- fi
- i=`expr ${i} + 1`
-done
-# Output: 6
diff --git a/codes/shell/demos/statement/case-demo.sh b/codes/shell/demos/statement/case-demo.sh
deleted file mode 100644
index d8302edf..00000000
--- a/codes/shell/demos/statement/case-demo.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-
-echo "input param: " $1 $2 $3
-
-x=0
-if [[ -n $1 ]]; then
- x=$1
-fi
-
-y=0
-if [[ -n $2 ]]; then
- y=$2
-fi
-
-oper=""
-if [[ -n $3 ]]; then
- oper=$3
-fi
-
-exec
-case ${oper} in
- "+")
- val=`expr ${x} + ${y}`
- echo "${x} + ${y} = ${val}"
- ;;
- "-")
- val=`expr ${x} - ${y}`
- echo "${x} - ${y} = ${val}"
- ;;
- "*")
- val=`expr ${x} \* ${y}`
- echo "${x} * ${y} = ${val}"
- ;;
- "/")
- val=`expr ${x} / ${y}`
- echo "${x} / ${y} = ${val}"
- ;;
- *)
- echo "Unknown oper!"
- ;;
-esac
diff --git a/codes/shell/demos/statement/continue-demo.sh b/codes/shell/demos/statement/continue-demo.sh
deleted file mode 100644
index 035d95c9..00000000
--- a/codes/shell/demos/statement/continue-demo.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-# 打印10以内的奇数
-for (( i = 0; i < 10; i ++ )); do
- if [[ $((i % 2)) -eq 0 ]]; then
- continue;
- fi
- echo ${i}
-done
-# Output:
-# 1
-# 3
-# 5
-# 7
-# 9
diff --git a/codes/shell/demos/statement/for-demo.sh b/codes/shell/demos/statement/for-demo.sh
deleted file mode 100644
index ba1aec98..00000000
--- a/codes/shell/demos/statement/for-demo.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env bash
-
-################### for 语句 ###################
-echo "print 0 to 9"
-for (( j = 0; j < 10; j ++ )); do
- echo ${j}
-done
-# Output:
-# print 0 to 9
-# 0
-# 1
-# 2
-# 3
-# 4
-# 5
-# 6
-# 7
-# 8
-# 9
-
-################### for in 语句 ###################
-echo "print 1 to 5"
-for i in {1..5}; do echo ${i}; done
-# Output:
-# print 1 to 5
-# 1
-# 2
-# 3
-# 4
-# 5
-
-################### for in 语句遍历文件 ###################
-DIR=/home/zp
-for FILE in ${DIR}/*.sh; do
- mv "$FILE" "${DIR}/scripts"
-done
-# 将 /home/zp 目录下所有 sh 文件拷贝到 /home/zp/scripts
diff --git a/codes/shell/demos/statement/until-demo.sh b/codes/shell/demos/statement/until-demo.sh
deleted file mode 100644
index 320b5909..00000000
--- a/codes/shell/demos/statement/until-demo.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-
-x=0
-until [[ ${x} -ge 5 ]]; do
- echo ${x}
- x=`expr ${x} + 1`
-done
-# Output:
-# 0
-# 1
-# 2
-# 3
-# 4
diff --git a/codes/shell/demos/statement/while-demo.sh b/codes/shell/demos/statement/while-demo.sh
deleted file mode 100644
index 375bed9e..00000000
--- a/codes/shell/demos/statement/while-demo.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bash
-
-### 0到9之间每个数的平方
-x=0
-### x小于10
-while [[ ${x} -lt 10 ]]; do
- echo $((x * x))
- x=$((x + 1))
-done
-# Output:
-# 0
-# 1
-# 4
-# 9
-# 16
-# 25
-# 36
-# 49
-# 64
-# 81
diff --git a/codes/shell/demos/string-demo.sh b/codes/shell/demos/string-demo.sh
deleted file mode 100644
index 652c57ae..00000000
--- a/codes/shell/demos/string-demo.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env bash
-
-################### 单引号和双引号 ###################
-################### 拼接字符串 ###################
-# 使用单引号拼接
-name1='white'
-str1='hello, '${name1}''
-str2='hello, ${name1}'
-echo ${str1}_${str2}
-# Output:
-# hello, white_hello, ${name1}
-
-# 使用双引号拼接
-name2="black"
-str3="hello, "${name2}""
-str4="hello, ${name2}"
-echo ${str3}_${str4}
-# Output:
-# hello, black_hello, black
-
-################### 获取字符串长度 ###################
-text="12345"
-echo ${#text}
-# Output:
-# 5
-
-################### 获取字符串长度 ###################
-text="12345"
-echo ${text:2:2}
-# Output:
-# 34
-
-################### 查找子字符串 ###################
-text="hello"
-echo `expr index "${text}" ll`
-# Output:
-# 3
-
-################### 截取关键字左边内容 ###################
-str="feature/1.0.0"
-branch=`echo ${str#feature/}`
-echo "branch is ${branch}"
-
-################### 截取关键字右边内容 ###################
-key=`echo ${str%/1.0.0}`
-echo "key is ${key}"
-
-################### 判断字符串中是否包含子字符串 ###################
-result=$(echo "${str}" | grep "feature/")
-if [[ "$result" != "" ]] ; then
- echo "feature/ 是 ${str} 的子字符串"
-else
- echo "feature/ 不是 ${str} 的子字符串"
-fi
diff --git a/codes/shell/demos/variable-demo.sh b/codes/shell/demos/variable-demo.sh
deleted file mode 100644
index c7acaa17..00000000
--- a/codes/shell/demos/variable-demo.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-################### 声明变量 ###################
-word="hello"
-echo ${word}
-# Output: hello
-
-################### 只读变量 ###################
-rword="hello"
-echo ${rword}
-# Output: hello
-readonly rword
-# rword="bye" # 如果放开注释,执行时会报错
-
-################### 删除变量 ###################
-dword="hello" # 声明变量
-echo ${dword} # 输出变量值
-# Output: hello
-
-unset dword # 删除变量
-echo ${dword}
-# Output: (空)
diff --git a/codes/shell/lib/env.sh b/codes/shell/lib/env.sh
new file mode 100644
index 00000000..4c41818e
--- /dev/null
+++ b/codes/shell/lib/env.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+
+# ------------------------------------------------------------------------------ 颜色状态
+
+# Regular Color
+C_BLACK="\033[0;30m"
+C_RED="\033[0;31m"
+C_GREEN="\033[0;32m"
+C_YELLOW="\033[0;33m"
+C_BLUE="\033[0;34m"
+C_MAGENTA="\033[0;35m"
+C_CYAN="\033[0;36m"
+C_WHITE="\033[0;37m"
+
+# Bold Color
+C_B_BLACK="\033[1;30m"
+C_B_RED="\033[1;31m"
+C_B_GREEN="\033[1;32m"
+C_B_YELLOW="\033[1;33m"
+C_B_BLUE="\033[1;34m"
+C_B_MAGENTA="\033[1;35m"
+C_B_CYAN="\033[1;36m"
+C_B_WHITE="\033[1;37m"
+
+# Underline Color
+C_U_BLACK="\033[4;30m"
+C_U_RED="\033[4;31m"
+C_U_GREEN="\033[4;32m"
+C_U_YELLOW="\033[4;33m"
+C_U_BLUE="\033[4;34m"
+C_U_MAGENTA="\033[4;35m"
+C_U_CYAN="\033[4;36m"
+C_U_WHITE="\033[4;37m"
+
+# Background Color
+C_BG_BLACK="\033[40m"
+C_BG_RED="\033[41m"
+C_BG_GREEN="\033[42m"
+C_BG_YELLOW="\033[43m"
+C_BG_BLUE="\033[44m"
+C_BG_MAGENTA="\033[45m"
+C_BG_CYAN="\033[46m"
+C_BG_WHITE="\033[47m"
+
+# Reset Color
+C_RESET="$(tput sgr0)"
+
+# ------------------------------------------------------------------------------ 常用状态值
+
+YES=0
+NO=1
+SUCCEED=0
+FAILED=1
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/mysql/SQL\346\211\271\345\244\204\347\220\206\346\211\247\350\241\214\350\204\232\346\234\254.sh" "b/codes/shell/mysql/SQL\346\211\271\345\244\204\347\220\206\346\211\247\350\241\214\350\204\232\346\234\254.sh"
similarity index 59%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/mysql/SQL\346\211\271\345\244\204\347\220\206\346\211\247\350\241\214\350\204\232\346\234\254.sh"
rename to "codes/shell/mysql/SQL\346\211\271\345\244\204\347\220\206\346\211\247\350\241\214\350\204\232\346\234\254.sh"
index e74299d2..89c92fc0 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/mysql/SQL\346\211\271\345\244\204\347\220\206\346\211\247\350\241\214\350\204\232\346\234\254.sh"
+++ "b/codes/shell/mysql/SQL\346\211\271\345\244\204\347\220\206\346\211\247\350\241\214\350\204\232\346\234\254.sh"
@@ -6,7 +6,7 @@ database='test'
for f in `ls */*.sql`
do
-echo ${f};
-mysql -u${user} -p${password} -f ${database} -e "source $f";
+ echo ${f};
+ mysql -u${user} -p${password} -f ${database} -e "source $f";
done
echo 'OK!'
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/mysql/\345\220\221\346\225\260\346\215\256\345\272\223\344\270\255\346\217\222\345\205\245\346\225\260\346\215\256.sh" "b/codes/shell/mysql/\345\220\221\346\225\260\346\215\256\345\272\223\344\270\255\346\217\222\345\205\245\346\225\260\346\215\256.sh"
similarity index 88%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/mysql/\345\220\221\346\225\260\346\215\256\345\272\223\344\270\255\346\217\222\345\205\245\346\225\260\346\215\256.sh"
rename to "codes/shell/mysql/\345\220\221\346\225\260\346\215\256\345\272\223\344\270\255\346\217\222\345\205\245\346\225\260\346\215\256.sh"
index c2eaef4c..c57f31fc 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/mysql/\345\220\221\346\225\260\346\215\256\345\272\223\344\270\255\346\217\222\345\205\245\346\225\260\346\215\256.sh"
+++ "b/codes/shell/mysql/\345\220\221\346\225\260\346\215\256\345\272\223\344\270\255\346\217\222\345\205\245\346\225\260\346\215\256.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# send data to the the table in the MYSQL database
MYSQL=`which mysql`
@@ -9,7 +10,7 @@ then
else
#脚本变量一定要用双引号,字符串变量使用单引号
statement=" insert into em_admin values(NULL, '$1', $2)"
- $MYSQL emwjs -u test <
+
+# Why is this change happening, e.g. goals, use cases, stories, etc.?
+Why:
+
+# How is this change happening, e.g. implementations, algorithms, etc.?
+How:
+
+# Tags suitable for searching, such as hashtags, keywords, etc.
+Tags:
+
+# ## Help ##
+#
+# Subject line imperative uppercase verbs:
+#
+# Add = Create a capability e.g. feature, test, dependency.
+# Drop = Delete a capability e.g. feature, test, dependency.
+# Fix = Fix an issue e.g. bug, typo, accident, misstatement.
+# Bump = Increase the version of something e.g. a dependency.
+# Make = Change the build process, or tools, or infrastructure.
+# Start = Begin doing something; e.g. enable a toggle, feature flag, etc.
+# Stop = End doing something; e.g. disable a toggle, feature flag, etc.
+# Refactor = A change that MUST be just refactoring.
+# Reformat = A change that MUST be just format, e.g. indent line, trim space, etc.
+# Rephrase = A change that MUST be just textual, e.g. edit a comment, doc, etc.
+# Optimize = A change that MUST be just about performance, e.g. speed up code.
+# Document = A change that MUST be only in the documentation, e.g. help files.
+#
+# For the subject line:
+# * Use 50 characters maximum.
+# * Do not use a sentence-ending period.
+#
+# For the body text:
+# * Use as many lines as you like.
+# * Use 72 characters maximum per line for typical word wrap text.
+#
+#
+# ## About ##
+#
+# This is our git commit messages.
+# You can edit this template if you want
+#
+# ## Usage ##
+#
+# Put the template file here:
+#
+# ~/.git_commit_template.txt
+#
+# Configure git to use the template file by running:
+#
+# git config --global commit.template ~/.git_commit_template.txt
+#
+# Add the template file to the ~/.gitconfig file:
+#
+# [commit]
+# template = ~/.git_commit_template.txt
+#
+# you could put it in other location if you prefer
+#
diff --git "a/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\345\210\233\345\273\272\344\270\264\346\227\266\346\226\207\344\273\266.sh" "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\345\210\233\345\273\272\344\270\264\346\227\266\346\226\207\344\273\266.sh"
new file mode 100644
index 00000000..cf294d73
--- /dev/null
+++ "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\345\210\233\345\273\272\344\270\264\346\227\266\346\226\207\344\273\266.sh"
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+tempFile=`mktemp test.XXXXXX`
+
+exec 3> ${tempFile}
+
+echo "This script writes to temp file ${tempFile}"
+echo "This is the first line" >&3
+echo "This is the second line" >&3
+echo "This is the last line" >&3
+
+exec 3>&-
+
+echo "Done creating temp file. The contents are:"
+cat ${tempFile}
+
+rm -f ${tempFile} 2> /dev/null
+
diff --git "a/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\345\210\233\345\273\272\344\270\264\346\227\266\347\233\256\345\275\225.sh" "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\345\210\233\345\273\272\344\270\264\346\227\266\347\233\256\345\275\225.sh"
new file mode 100644
index 00000000..de2454e8
--- /dev/null
+++ "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\345\210\233\345\273\272\344\270\264\346\227\266\347\233\256\345\275\225.sh"
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+tempDir=`mktemp -d dir.XXXXXX`
+cd ${tempDir} || exit 1
+
+tempFile1=`mktemp temp.XXXXXX`
+tempFile2=`mktemp temp.XXXXXX`
+exec 7> ${tempFile1}
+exec 8> ${tempFile2}
+
+echo "Sending data to directory $tempDir"
+echo "This is a test line of data for $tempFile1" >&7
+echo "This is a test line of data for $tempFile2" >&8
+
diff --git "a/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\346\226\207\344\273\266\350\267\257\345\276\204\346\223\215\344\275\234.sh" "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\346\226\207\344\273\266\350\267\257\345\276\204\346\223\215\344\275\234.sh"
new file mode 100644
index 00000000..a246d253
--- /dev/null
+++ "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\346\226\207\344\273\266\350\267\257\345\276\204\346\223\215\344\275\234.sh"
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+path=/dir1/dir2/dir3/test.txt
+echo ${path##*/} 获取文件名 test.txt
+echo ${path##*.} 获取后缀 txt
+
+#不带后缀的文件名
+temp=${path##*/}
+echo ${temp%.*} test
+
+#获取目录
+echo ${path%/*} /dir1/dir2/dir3
diff --git "a/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\347\233\256\345\275\225\345\237\272\346\234\254\346\223\215\344\275\234.sh" "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\347\233\256\345\275\225\345\237\272\346\234\254\346\223\215\344\275\234.sh"
new file mode 100644
index 00000000..cd020681
--- /dev/null
+++ "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\347\233\256\345\275\225\345\237\272\346\234\254\346\223\215\344\275\234.sh"
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+# ------------------------------------------------------------------------------
+# 目录操作示例
+# @author: Zhang Peng
+# ------------------------------------------------------------------------------
+
+# 创建目录(整个文件路径中的目录如果不存在,都会一一创建,如果目录已存在,则什么也不做)
+mkdir -p /home/linux-tutorial/temp
+
+# 进入目录,如果失败,则退出脚本
+cd /home/linux-tutorial/temp || exit 1
+
+# 获取当前目录路径
+CURRENT_DIR=$(pwd)
+echo "当前目录是:${CURRENT_DIR}"
+
+# 获取上一级目录路径
+PARENT_DIR=$(dirname $(pwd))
+echo "父目录是:${PARENT_DIR}"
+
+# 获取当前执行脚本名
+DIR_NAME=$(basename $0)
+echo "当前执行脚本名是:${DIR_NAME}"
+
+# 复制目录(复制 temp 目录所有内容,并命名新文件夹叫 temp2)
+cp -rf /home/linux-tutorial/temp /home/linux-tutorial/temp2
+
+# 移动目录(将 temp2 移到 temp 目录下)
+mv /home/linux-tutorial/temp2 /home/linux-tutorial/temp/temp2
+
+# 删除目录
+rm -rf /home/linux-tutorial
diff --git "a/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\350\257\273\346\226\207\344\273\266.sh" "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\350\257\273\346\226\207\344\273\266.sh"
new file mode 100644
index 00000000..d9f14cd8
--- /dev/null
+++ "b/codes/shell/\346\226\207\344\273\266\346\223\215\344\275\234/\350\257\273\346\226\207\344\273\266.sh"
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+FILE=log.txt
+
+count=1
+cat ${FILE} | while read line
+do
+ echo "$count: $line"
+ count=$[ $count + 1 ]
+done
+echo "Finished reading."
+
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk.sh"
similarity index 85%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk.sh"
index 15f60884..6baee2eb 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
BEGIN {
print "The latest list of users and shells"
@@ -8,7 +8,7 @@ FS=":"
}
{
-print $1 " " $7
+ print $1 " " $7
}
END {
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\345\207\275\346\225\260\345\272\223" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\345\207\275\346\225\260\345\272\223"
similarity index 55%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\345\207\275\346\225\260\345\272\223"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\345\207\275\346\225\260\345\272\223"
index c6673c1c..99bc48d7 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\345\207\275\346\225\260\345\272\223"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\345\207\275\346\225\260\345\272\223"
@@ -5,8 +5,8 @@ function myprint()
printf "%-16s - %s", $1, $4
}
-function myrand(limit)
+function myrand ( limit )
{
- return int(limit * rand())
+return int ( limit * rand ( ) )
}
diff --git "a/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\350\204\232\346\234\254" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\350\204\232\346\234\254"
new file mode 100644
index 00000000..1028bcdf
--- /dev/null
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\350\204\232\346\234\254"
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+BEGIN{ FS="\n";
+RS=""}
+{
+myprint()
+
+}
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/script" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/script"
similarity index 100%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/script"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/script"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/test" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/test"
similarity index 100%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/test"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/test"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\345\217\230\351\207\217.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\345\217\230\351\207\217.sh"
similarity index 97%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\345\217\230\351\207\217.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\345\217\230\351\207\217.sh"
index 32382c80..51f26513 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\345\217\230\351\207\217.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\345\217\230\351\207\217.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#使用内建变量
# NF 当前记录的字段个数
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\346\250\241\345\274\217\357\274\214\347\273\223\346\236\204\345\214\226\345\221\275\344\273\244.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\346\250\241\345\274\217\357\274\214\347\273\223\346\236\204\345\214\226\345\221\275\344\273\244.sh"
similarity index 91%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\346\250\241\345\274\217\357\274\214\347\273\223\346\236\204\345\214\226\345\221\275\344\273\244.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\346\250\241\345\274\217\357\274\214\347\273\223\346\236\204\345\214\226\345\221\275\344\273\244.sh"
index 4e2a3fca..6e61f422 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\346\250\241\345\274\217\357\274\214\347\273\223\346\236\204\345\214\226\345\221\275\344\273\244.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\344\275\277\347\224\250\346\250\241\345\274\217\357\274\214\347\273\223\346\236\204\345\214\226\345\221\275\344\273\244.sh"
@@ -1,7 +1,8 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#正则表达式
-gawk 'BEGIN{FS=","}
+gawk 'BEGIN{FS=","}
/11/{print $1}
' test
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.sh"
similarity index 85%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.sh"
index 4f58519f..a026581a 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#gawk 自定义函数
gawk '
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\260\203\347\224\250\345\207\275\346\225\260\345\272\223\345\222\214\350\204\232\346\234\254.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\260\203\347\224\250\345\207\275\346\225\260\345\272\223\345\222\214\350\204\232\346\234\254.sh"
similarity index 78%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\260\203\347\224\250\345\207\275\346\225\260\345\272\223\345\222\214\350\204\232\346\234\254.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\260\203\347\224\250\345\207\275\346\225\260\345\272\223\345\222\214\350\204\232\346\234\254.sh"
index 0ffaa675..fc871ed5 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\260\203\347\224\250\345\207\275\346\225\260\345\272\223\345\222\214\350\204\232\346\234\254.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\260\203\347\224\250\345\207\275\346\225\260\345\272\223\345\222\214\350\204\232\346\234\254.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#使用函数库和gawk脚本
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\276\223\345\207\272.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\276\223\345\207\272.sh"
similarity index 97%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\276\223\345\207\272.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\276\223\345\207\272.sh"
index 3fff2fdb..a26f5c72 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\276\223\345\207\272.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/\350\276\223\345\207\272.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#print用于产生简单输出
#多个表达式的字符串值之间用输出字段分隔符分开
@@ -62,5 +62,5 @@ END{ for(c in pop) printf("%15-s%6d\n", c, pop[c]) | "sort -nk 2"; close("sort -
#在同一个程序中,如果你写了一个文件,而待会儿想要读取它,那么就需要调用close。
#某一时刻,同时处于打开状态的文件或管道数量最大值由实现定义。
-close("sort -nk 2")
+close ( " sort -nk 2 " )
diff --git "a/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/grep.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/grep.sh"
new file mode 100644
index 00000000..548d53f9
--- /dev/null
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/grep.sh"
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+# 使用 grep 命令可以用于在文件中查找指定文本
+
+# 在二进制文件中查找字符串
+file=$1
+keyword=$2
+strings ${file} | grep ${keyword}
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\347\233\256\345\275\225\346\226\207\344\273\266\350\256\241\346\225\260.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\347\233\256\345\275\225\346\226\207\344\273\266\350\256\241\346\225\260.sh"
similarity index 92%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\347\233\256\345\275\225\346\226\207\344\273\266\350\256\241\346\225\260.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\347\233\256\345\275\225\346\226\207\344\273\266\350\256\241\346\225\260.sh"
index 689ca6f8..af048364 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\347\233\256\345\275\225\346\226\207\344\273\266\350\256\241\346\225\260.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\347\233\256\345\275\225\346\226\207\344\273\266\350\256\241\346\225\260.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# count number of files in your PATH
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\351\202\256\344\273\266\351\252\214\350\257\201.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\351\202\256\344\273\266\351\252\214\350\257\201.sh"
similarity index 84%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\351\202\256\344\273\266\351\252\214\350\257\201.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\351\202\256\344\273\266\351\252\214\350\257\201.sh"
index 1857ac8c..e5e28abd 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\351\202\256\344\273\266\351\252\214\350\257\201.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/regex/\351\202\256\344\273\266\351\252\214\350\257\201.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#验证邮件
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\346\226\207\344\273\266\346\223\215\344\275\234.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\346\226\207\344\273\266\346\223\215\344\275\234.sh"
similarity index 93%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\346\226\207\344\273\266\346\223\215\344\275\234.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\346\226\207\344\273\266\346\223\215\344\275\234.sh"
index 046001ef..9185c9ef 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\346\226\207\344\273\266\346\223\215\344\275\234.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\346\226\207\344\273\266\346\223\215\344\275\234.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#向文件写入
sed '1,2w test1' test1
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\347\274\226\350\276\221\345\231\250\345\237\272\347\241\200.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\347\274\226\350\276\221\345\231\250\345\237\272\347\241\200.sh"
similarity index 98%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\347\274\226\350\276\221\345\231\250\345\237\272\347\241\200.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\347\274\226\350\276\221\345\231\250\345\237\272\347\241\200.sh"
index 011c93f4..06e9c46c 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\347\274\226\350\276\221\345\231\250\345\237\272\347\241\200.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/sed\347\274\226\350\276\221\345\231\250\345\237\272\347\241\200.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#sed编辑器基础
#替换标记
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/test" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/test"
similarity index 100%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/test"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/test"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\344\277\235\346\214\201\347\251\272\351\227\264.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\344\277\235\346\214\201\347\251\272\351\227\264.sh"
similarity index 92%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\344\277\235\346\214\201\347\251\272\351\227\264.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\344\277\235\346\214\201\347\251\272\351\227\264.sh"
index 3c75f7de..0772420b 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\344\277\235\346\214\201\347\251\272\351\227\264.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\344\277\235\346\214\201\347\251\272\351\227\264.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#h将模式空间保存到保持空间
#H将模式空间附加到保持空间
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\210\240\351\231\244\346\214\207\345\256\232\347\232\204\347\251\272\347\231\275\350\241\214\345\222\214\345\210\240\351\231\244html\346\240\207\347\255\276.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\210\240\351\231\244\346\214\207\345\256\232\347\232\204\347\251\272\347\231\275\350\241\214\345\222\214\345\210\240\351\231\244html\346\240\207\347\255\276.sh"
similarity index 93%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\210\240\351\231\244\346\214\207\345\256\232\347\232\204\347\251\272\347\231\275\350\241\214\345\222\214\345\210\240\351\231\244html\346\240\207\347\255\276.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\210\240\351\231\244\346\214\207\345\256\232\347\232\204\347\251\272\347\231\275\350\241\214\345\222\214\345\210\240\351\231\244html\346\240\207\347\255\276.sh"
index 2dcdd57c..d37ebaa9 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\210\240\351\231\244\346\214\207\345\256\232\347\232\204\347\251\272\347\231\275\350\241\214\345\222\214\345\210\240\351\231\244html\346\240\207\347\255\276.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\210\240\351\231\244\346\214\207\345\256\232\347\232\204\347\251\272\347\231\275\350\241\214\345\222\214\345\210\240\351\231\244html\346\240\207\347\255\276.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#多个空格只保留一个
#sed '/./,/^$/!d' test
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250sed.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250sed.sh"
similarity index 79%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250sed.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250sed.sh"
index 41afaf13..5a1a5fa0 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250sed.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250sed.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# shell wrapper for sed editor script to reverse lines
sed -n '{
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\216\222\351\231\244\345\221\275\344\273\244.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\216\222\351\231\244\345\221\275\344\273\244.sh"
similarity index 100%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\216\222\351\231\244\345\221\275\344\273\244.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\216\222\351\231\244\345\221\275\344\273\244.sh"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\250\241\345\274\217\346\233\277\344\273\243.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\250\241\345\274\217\346\233\277\344\273\243.sh"
similarity index 95%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\250\241\345\274\217\346\233\277\344\273\243.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\250\241\345\274\217\346\233\277\344\273\243.sh"
index 8682f6ed..70585d17 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\250\241\345\274\217\346\233\277\344\273\243.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\250\241\345\274\217\346\233\277\344\273\243.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#and符号,代表替换命令中的匹配模式,不管预定义模式是什么文本,都可以用and符号替换,and符号会提取匹配替换命令中指定替换模式中的所有字符串
echo "The cat sleeps in his hat" | sed 's/.at/"&"/g'
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\265\213\350\257\225.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\265\213\350\257\225.sh"
similarity index 91%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\265\213\350\257\225.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\265\213\350\257\225.sh"
index 65ef7064..88befd75 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\265\213\350\257\225.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\346\265\213\350\257\225.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#测试,如果测试成功,如果没有标签,sed会跳转到结尾,如果有标签,就跳转到标签,如果测试失败,则不会跳转
sed -n '{s/first/matched/; t; s/This is the/No match on/}' test
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\347\273\231\346\226\207\344\273\266\344\270\255\347\232\204\350\241\214\347\274\226\345\217\267.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\347\273\231\346\226\207\344\273\266\344\270\255\347\232\204\350\241\214\347\274\226\345\217\267.sh"
similarity index 62%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\347\273\231\346\226\207\344\273\266\344\270\255\347\232\204\350\241\214\347\274\226\345\217\267.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\347\273\231\346\226\207\344\273\266\344\270\255\347\232\204\350\241\214\347\274\226\345\217\267.sh"
index 07bd0e69..9ed6f148 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\347\273\231\346\226\207\344\273\266\344\270\255\347\232\204\350\241\214\347\274\226\345\217\267.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\347\273\231\346\226\207\344\273\266\344\270\255\347\232\204\350\241\214\347\274\226\345\217\267.sh"
@@ -1,3 +1,3 @@
-#!/bin/bash
+#!/usr/bin/env bash
sed '=' test | sed 'N; s/\n/ /'
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\267\263\350\275\254.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\267\263\350\275\254.sh"
similarity index 92%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\267\263\350\275\254.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\267\263\350\275\254.sh"
index 69eff6b1..a352ad5e 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\267\263\350\275\254.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\267\263\350\275\254.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
#跳转到指定脚本
sed '{/first/b jump1; s/This is the/No jump on/; :jump1; s/This is the/Jump here on/}' test
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\276\223\345\207\272\346\234\253\345\260\276\346\214\207\345\256\232\350\241\214\346\225\260\347\232\204\346\225\260\346\215\256.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\276\223\345\207\272\346\234\253\345\260\276\346\214\207\345\256\232\350\241\214\346\225\260\347\232\204\346\225\260\346\215\256.sh"
similarity index 77%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\276\223\345\207\272\346\234\253\345\260\276\346\214\207\345\256\232\350\241\214\346\225\260\347\232\204\346\225\260\346\215\256.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\276\223\345\207\272\346\234\253\345\260\276\346\214\207\345\256\232\350\241\214\346\225\260\347\232\204\346\225\260\346\215\256.sh"
index eb0f2adb..8bddf0ec 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\276\223\345\207\272\346\234\253\345\260\276\346\214\207\345\256\232\350\241\214\346\225\260\347\232\204\346\225\260\346\215\256.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\350\276\223\345\207\272\346\234\253\345\260\276\346\214\207\345\256\232\350\241\214\346\225\260\347\232\204\346\225\260\346\215\256.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#输出末尾10行数据
sed '{
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\351\207\215\345\256\232\345\220\221sed\350\276\223\345\207\272.sh" "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\351\207\215\345\256\232\345\220\221sed\350\276\223\345\207\272.sh"
similarity index 93%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\351\207\215\345\256\232\345\220\221sed\350\276\223\345\207\272.sh"
rename to "codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\351\207\215\345\256\232\345\220\221sed\350\276\223\345\207\272.sh"
index ec05cf1f..674afaa3 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\351\207\215\345\256\232\345\220\221sed\350\276\223\345\207\272.sh"
+++ "b/codes/shell/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/sed/\351\207\215\345\256\232\345\220\221sed\350\276\223\345\207\272.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# add commas to numbers in factorial answer
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\345\237\272\346\234\254\350\204\232\346\234\254/\344\275\277\347\224\250\350\207\252\345\256\232\344\271\211\345\217\230\351\207\217.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\345\237\272\346\234\254\350\204\232\346\234\254/\344\275\277\347\224\250\350\207\252\345\256\232\344\271\211\345\217\230\351\207\217.sh"
deleted file mode 100644
index 5dd633d4..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\345\237\272\346\234\254\350\204\232\346\234\254/\344\275\277\347\224\250\350\207\252\345\256\232\344\271\211\345\217\230\351\207\217.sh"
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-#testing variables
-
-days=10
-guest="Katie"
-echo "$guest logged in $days days age"
-guest="Katie2"
-days=5
-echo "$guest logged in $days days age"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\350\204\232\346\234\254" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\350\204\232\346\234\254"
deleted file mode 100644
index 35597f9c..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\346\237\245\346\211\276\346\233\277\346\215\242\346\226\207\346\234\254/gawk/gawk\350\204\232\346\234\254"
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-BEGIN{FS="\n"; RS=""}
-{
- myprint()
-}
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\272\223\345\207\275\346\225\260.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\272\223\345\207\275\346\225\260.sh"
deleted file mode 100644
index 4b048c3c..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\272\223\345\207\275\346\225\260.sh"
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-#using a library file the wrong way
-
-. ./脚本库.sh
-
-result=`addem 10 15`
-echo "The result is $result"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\350\204\232\346\234\254\345\272\223.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\350\204\232\346\234\254\345\272\223.sh"
deleted file mode 100644
index 1c52b0f9..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\350\204\232\346\234\254\345\272\223.sh"
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-
-# myscript functions
-
-function addem {
- echo $[ $1 + $2 ]
-}
-
-function multem {
- echo $[ $1 * $2 ]
-}
-
-function divem {
- if [ $2 -ne 0]
- then
- echo $[ $1/$2 ]
- else
- echo -1
- fi
-}
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\273\216\346\226\207\344\273\266\344\270\255\350\257\273\345\217\226\346\225\260\346\215\256.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\273\216\346\226\207\344\273\266\344\270\255\350\257\273\345\217\226\346\225\260\346\215\256.sh"
deleted file mode 100644
index 015c852f..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\273\216\346\226\207\344\273\266\344\270\255\350\257\273\345\217\226\346\225\260\346\215\256.sh"
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-# reading data from a file
-
-count=1
-cat test | while read line
-do
- echo "Line $count: $line"
- count=$[ $count + 1 ]
-done
-echo "Finished processing the file"
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts.sh"
deleted file mode 100644
index 63389393..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts.sh"
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-# simple demonstration of the getopts command
-
-while getopts :ab:c opt
-do
- case "$opt" in
- a) echo "Found the -a option";;
- b) echo "Found the -b option, with value $OPTARG";;
- c) echo "Found the -c option";;
- *) echo "Unknown option:$opt";;
- esac
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\206\347\246\273\345\217\202\346\225\260\345\222\214\351\200\211\351\241\271.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\206\347\246\273\345\217\202\346\225\260\345\222\214\351\200\211\351\241\271.sh"
deleted file mode 100644
index ee3da94c..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\206\347\246\273\345\217\202\346\225\260\345\222\214\351\200\211\351\241\271.sh"
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-
-#extracting options and parameters
-
-while [ -n "$1" ]
-do
- case "$1" in
- -a) echo "Found the -a option";;
- -b) echo "Found the -b option";;
- -c) echo "Found the -c option";;
- --) shift
- break;;
- *) echo "$1 is not an option";;
- esac
- shift
-done
-
-count=1
-for param in $@
-do
- echo "Parameter #$count: $param"
- count=$[ $count + 1 ]
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\344\270\264\346\227\266\347\233\256\345\275\225.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\344\270\264\346\227\266\347\233\256\345\275\225.sh"
deleted file mode 100644
index 8409e2cc..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\344\270\264\346\227\266\347\233\256\345\275\225.sh"
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-
-# using a temporary directory
-
-tempdir=`mktemp -d dir.XXXXXX`
-cd $tempdir
-
-tempfile1=`mktemp temp.XXXXXX`
-tempfile2=`mktemp temp.XXXXXX`
-exec 7> $tempfile1
-exec 8> $tempfile2
-
-echo "Sending data to directory $tempdir"
-echo "This is a test line of data for $tempfile1" >&7
-echo "This is a test line of data for $tempfile2" >&8
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\346\234\254\345\234\260\344\270\264\346\227\266\346\226\207\344\273\266.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\346\234\254\345\234\260\344\270\264\346\227\266\346\226\207\344\273\266.sh"
deleted file mode 100644
index 6d15a9de..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\346\234\254\345\234\260\344\270\264\346\227\266\346\226\207\344\273\266.sh"
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-
-# creating and using a temp file
-
-tempfile=`mktemp test.XXXXXX`
-
-exec 3>$tempfile
-
-echo "This script writes to temp file $tempfile"
-
-echo "This is the first line" >&3
-echo "This is the second line" >&3
-echo "This is the last line" >&3
-
-exec 3>&-
-
-echo "Done creating temp file. The contents are:"
-
-cat $tempfile
-
-rm -f $tempfile 2>/dev/null
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\234\250tmp\347\233\256\345\275\225\345\210\233\345\273\272\344\270\264\346\227\266\346\226\207\344\273\266.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\234\250tmp\347\233\256\345\275\225\345\210\233\345\273\272\344\270\264\346\227\266\346\226\207\344\273\266.sh"
deleted file mode 100644
index a4497a18..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\234\250tmp\347\233\256\345\275\225\345\210\233\345\273\272\344\270\264\346\227\266\346\226\207\344\273\266.sh"
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-# creating a temp file in /tmp
-
-tempfile=`mktemp -t tmp.XXXXXX`
-
-echo "This is a test file" > $tempfile
-echo "This is the second line of the test" >> $tempfile
-
-echo ”The temp is locate at : $tempfile“
-cat $tempfile
-rm -f $tempfile
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\347\256\200\345\215\225\351\200\211\351\241\271.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\347\256\200\345\215\225\351\200\211\351\241\271.sh"
deleted file mode 100644
index 60dd4040..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\347\256\200\345\215\225\351\200\211\351\241\271.sh"
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-# extracting command line options as parameters
-
-while [ -n "$1" ]
-do
- case "$1" in
- -a) echo "Found the -a option";;
- -b) echo "Found the -b optins";;
- -c) echo "Found the -c optins";;
- *) echo "$1 is not a valid options";;
- esac
- shift
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/continue\351\200\200\345\207\272\345\244\232\345\261\202\345\276\252\347\216\257.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/continue\351\200\200\345\207\272\345\244\232\345\261\202\345\276\252\347\216\257.sh"
deleted file mode 100644
index 96ae556e..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/continue\351\200\200\345\207\272\345\244\232\345\261\202\345\276\252\347\216\257.sh"
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-#continuing an outer loop
-
-for (( a=1; a<=5; a++))
-do
- echo "Iteration $a:"
- for (( b=1; b<3; b++ ))
- do
- if [ $a -gt 2 ] && [ $a -lt 4 ]
- then
- continue 2
- fi
- var3=$[ $a * $b ]
- echo " The result of $a * $b is $var3"
- done
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/if-then-else\350\257\255\345\217\245.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/if-then-else\350\257\255\345\217\245.sh"
deleted file mode 100644
index 41aae931..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/if-then-else\350\257\255\345\217\245.sh"
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-#testing the else section
-testuser=badtest
-if grep $testuser /etc/passwd
-then
- echo The files for user $testuser are:
- ls -a /home/.b*
-else
- echo "The user name $testuser does not exist on this system"
-fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/if-then\350\257\255\345\217\245.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/if-then\350\257\255\345\217\245.sh"
deleted file mode 100644
index 21b53a67..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/if-then\350\257\255\345\217\245.sh"
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-#testing the if statement
-if date
-then
- echo "it worked"
-fi
-echo -e '\n'
-if asd
-then
- echo "it not worked"
-fi
-echo 'We are outside the if statement'
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/while\351\207\214\351\235\242\345\265\214\345\245\227for\345\276\252\347\216\257.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/while\351\207\214\351\235\242\345\265\214\345\245\227for\345\276\252\347\216\257.sh"
deleted file mode 100644
index ab53b05d..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/while\351\207\214\351\235\242\345\265\214\345\245\227for\345\276\252\347\216\257.sh"
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-
-# placing a for loop inside a while loop
-
-var1=5
-
-while [ $var1 -ge 0 ]
-do
- echo "Outer loop: $var1"
- for (( var2=1; $var2 < 3; var2++))
- do
- var3=$[ $var1*$var2]
- echo "Inner loop: $var1 * $var2 = $var3"
- done
- var1=$[ $var1 - 1 ]
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\270\244\344\270\252for\345\265\214\345\245\227\345\276\252\347\216\257.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\270\244\344\270\252for\345\265\214\345\245\227\345\276\252\347\216\257.sh"
deleted file mode 100644
index 7bba122a..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\270\244\344\270\252for\345\265\214\345\245\227\345\276\252\347\216\257.sh"
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-#nesting for loops
-
-for (( a=1; a<=3; a++ ))
-do
- echo "Starting loop $a:"
- for (( b=1; b<=3; b++))
- do
- echo "Inside loog: $b:"
- done
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\273\216\345\217\230\351\207\217\350\257\273\345\217\226\345\210\227\350\241\250.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\273\216\345\217\230\351\207\217\350\257\273\345\217\226\345\210\227\350\241\250.sh"
deleted file mode 100644
index 43aad211..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\273\216\345\217\230\351\207\217\350\257\273\345\217\226\345\210\227\350\241\250.sh"
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-# using a variable to hold the list
-
-list="Alabama Alaska Arizona"
-list=$list" Connecticut"
-
-for state in $list
-do
- echo "Have you ever visited $state"
-done
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250C\350\257\255\350\250\200\351\243\216\346\240\274\347\232\204for\345\221\275\344\273\244.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250C\350\257\255\350\250\200\351\243\216\346\240\274\347\232\204for\345\221\275\344\273\244.sh"
deleted file mode 100644
index 8c869948..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250C\350\257\255\350\250\200\351\243\216\346\240\274\347\232\204for\345\221\275\344\273\244.sh"
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-#testing the C-style for loop
-
-for (( i=1; i<=10; i++ ))
-do
- echo "The next number is $i"
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250break\350\267\263\345\207\272\345\244\226\351\203\250\345\276\252\347\216\257.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250break\350\267\263\345\207\272\345\244\226\351\203\250\345\276\252\347\216\257.sh"
deleted file mode 100644
index f6a8ea95..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250break\350\267\263\345\207\272\345\244\226\351\203\250\345\276\252\347\216\257.sh"
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-# break n,默认为1
-
-for (( a=1; a<=3; a++ ))
-do
- echo "Outer loop : $a"
- for (( b=1; b < 100; b++ ))
- do
- if [ $b -gt 4 ]
- then
- break 2
- fi
- echo " Inner loop:$b"
- done
-done
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250case\350\257\255\345\217\245.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250case\350\257\255\345\217\245.sh"
deleted file mode 100644
index 8a742d85..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250case\350\257\255\345\217\245.sh"
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-#using the case command
-
-case $USER in
-tiandi | barbar)
- echo "Welcome, $USER"
- echo "Pleas enjoy your visit";;
-testing)
- echo "Special testing account";;
-jessica)
- echo "Do not forget to logout when you are out";;
-*)
- echo "Sorry, you are not allowed here";;
-esac
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250continue\345\221\275\344\273\244.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250continue\345\221\275\344\273\244.sh"
deleted file mode 100644
index 9d9e3a15..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250continue\345\221\275\344\273\244.sh"
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-#using the continue command
-
-for (( var1 = 1; var1 < 15; var1++ ))
-do
- if [ $var1 -gt 5 ] && [ $var1 -lt 10 ]
- then
- continue
- fi
- echo "Iteration number:$var1"
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250elif.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250elif.sh"
deleted file mode 100644
index ba231a0c..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250elif.sh"
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-# looking for a possible value
-
-if [ $USER = "tiandi" ]
-then
- echo "Welcome $USER"
- echo "Please enjoy your visit"
-elif [ $USER = testing ]
-then
- echo "Welcome $USER"
- echo "Please enjoy your visit"
-elif [ $USER = barbar ]
-then
- echo "Do not forget to logout when you're done"
-else
- echo "Sorry, you are not allowed here"
-fi
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250test\350\277\233\350\241\214\346\225\260\345\200\274\346\257\224\350\276\203.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250test\350\277\233\350\241\214\346\225\260\345\200\274\346\257\224\350\276\203.sh"
deleted file mode 100644
index 1220b204..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250test\350\277\233\350\241\214\346\225\260\345\200\274\346\257\224\350\276\203.sh"
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-var1=10
-var2=5
-if [ $var1 -gt 5 ]
-then
- echo "The test value $var1 is greater than 5"
-fi
-if [ $var1 -eq $var2 ]
-then
- echo "The values is equal"
-else
- echo "The values are different"
-fi
-
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250until\345\221\275\344\273\244.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250until\345\221\275\344\273\244.sh"
deleted file mode 100644
index 33732d4e..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250until\345\221\275\344\273\244.sh"
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-#using the until command
-
-var1=100
-until [ $var1 -eq 0 ]
-do
- echo $var1
- var1=$[ $var1-25 ]
-done
-
-var1=100
-until echo $var1
- [ $var1 -eq 0 ]
-do
- echo Inside the loop: $var1
- var1=$[ $var1 - 25 ]
-done
-
-
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250while.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250while.sh"
deleted file mode 100644
index e49d5bb9..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250while.sh"
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-# while command test
- var1=10
- while [ $var1 -gt 0 ]
- do
- echo $var1
- var1=$[ $var1 - 1 ]
-done
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250while\345\244\232\344\270\252\346\265\213\350\257\225\345\221\275\344\273\244.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250while\345\244\232\344\270\252\346\265\213\350\257\225\345\221\275\344\273\244.sh"
deleted file mode 100644
index c673e855..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250while\345\244\232\344\270\252\346\265\213\350\257\225\345\221\275\344\273\244.sh"
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-#testing a multicommand while loop
-
-var1=10
-while echo $var1
- [ $var1 -ge 0 ]
-do
- echo 'This is inside the loop'
- var1=$[ $var1 - 1 ]
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\345\274\225\345\217\267\345\234\210\350\265\267\347\224\250\347\251\272\346\240\274\345\210\206\351\232\224\347\232\204\345\255\227\347\254\246\344\270\262.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\345\274\225\345\217\267\345\234\210\350\265\267\347\224\250\347\251\272\346\240\274\345\210\206\351\232\224\347\232\204\345\255\227\347\254\246\344\270\262.sh"
deleted file mode 100644
index a965817e..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\345\274\225\345\217\267\345\234\210\350\265\267\347\224\250\347\251\272\346\240\274\345\210\206\351\232\224\347\232\204\345\255\227\347\254\246\344\270\262.sh"
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-# another example of how not to use the for command
-
-for test in Newada "New Hampshire"
-do
- echo "Now going to $test"
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\347\254\246\345\220\210\346\235\241\344\273\266\346\265\213\350\257\225.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\347\254\246\345\220\210\346\235\241\344\273\266\346\265\213\350\257\225.sh"
deleted file mode 100644
index 89f7a8fa..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\347\254\246\345\220\210\346\235\241\344\273\266\346\265\213\350\257\225.sh"
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-#testing compound comparisons
-
-if [ -d $HOME ] && [ -w $HOME/testing ]
-then
- echo "The file exists and you can write to it"
-else
- echo "I cannot write to it"
-fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\210\244\346\226\255\345\255\227\347\254\246\344\270\262\351\225\277\345\272\246\346\230\257\345\220\246\344\270\272\351\233\266.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\210\244\346\226\255\345\255\227\347\254\246\344\270\262\351\225\277\345\272\246\346\230\257\345\220\246\344\270\272\351\233\266.sh"
deleted file mode 100644
index 13114ccf..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\210\244\346\226\255\345\255\227\347\254\246\344\270\262\351\225\277\345\272\246\346\230\257\345\220\246\344\270\272\351\233\266.sh"
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-# testing string length
-
-#-n 判断长度是否非零
-#-z 判断长度是否为零
-
-val1=testing
-val2=''
-
-if [ -n "$val1" ]
-then
- echo "The string $val1 is not empty"
-else
- echo "The string $val1 is empty"
-fi
-
-if [ -z "$val2" ]
-then
- echo "The string $val2 is empty"
-else
- echo "The string $val2 is not empty"
-fi
-if [ -z "$val3" ]
-then
- echo "The string $val3 is empty"
-else
- echo "The string $val3 is not empty"
-fi
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\234\250for\350\257\255\345\217\245\344\270\255\344\275\277\347\224\250\345\244\232\344\270\252\345\217\230\351\207\217.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\234\250for\350\257\255\345\217\245\344\270\255\344\275\277\347\224\250\345\244\232\344\270\252\345\217\230\351\207\217.sh"
deleted file mode 100644
index 48d4118f..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\234\250for\350\257\255\345\217\245\344\270\255\344\275\277\347\224\250\345\244\232\344\270\252\345\217\230\351\207\217.sh"
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-# multiple variables
-
-for (( a=1, b=10; a<=10; a++,b-- ))
-do
- echo "$a - $b"
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\234\250then\345\235\227\344\270\255\344\275\277\347\224\250\345\244\232\346\235\241\345\221\275\344\273\244.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\234\250then\345\235\227\344\270\255\344\275\277\347\224\250\345\244\232\346\235\241\345\221\275\344\273\244.sh"
deleted file mode 100644
index a4d439c8..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\234\250then\345\235\227\344\270\255\344\275\277\347\224\250\345\244\232\346\235\241\345\221\275\344\273\244.sh"
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-#testing multiple commands in the then section
-testuser=tiandi
-if grep $testuser /etc/passwd
-then
- echo The bash files from user $testuser are:
- ls -a /home/$testuser/.b*
-fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\255\227\347\254\246\344\270\262\346\257\224\350\276\203.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\255\227\347\254\246\344\270\262\346\257\224\350\276\203.sh"
deleted file mode 100644
index 03827617..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\255\227\347\254\246\344\270\262\346\257\224\350\276\203.sh"
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-#testing string equality
-
-testuser=tiandi
-
-if [ $USER = $testuser ]
-then
- echo "Welcome $testuser"
-fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\265\214\345\245\227if.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\265\214\345\245\227if.sh"
deleted file mode 100644
index 05a7907c..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\345\265\214\345\245\227if.sh"
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\243\200\346\237\245\346\226\207\344\273\266\346\210\226\347\233\256\345\275\225\346\230\257\345\220\246\345\255\230\345\234\250.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\243\200\346\237\245\346\226\207\344\273\266\346\210\226\347\233\256\345\275\225\346\230\257\345\220\246\345\255\230\345\234\250.sh"
deleted file mode 100644
index f0380e83..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\243\200\346\237\245\346\226\207\344\273\266\346\210\226\347\233\256\345\275\225\346\230\257\345\220\246\345\255\230\345\234\250.sh"
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-# checking if a directory or a file exists
-
-if [ -e $HOME ]
-then
- echo "OK on the directory.now to check the file"
- #checking if a file exists
- if [ -e $HOME/testing ]
- then
- #the file exists,append data to it
- echo "Appending date to existing file"
- date >> $HOME/testing
- else
- #the file is not exists,create a new file
- echo "Creating a new file"
- date > $HOME/testing
- fi
-else
- echo 'Sorry. you do not have a $HOME directory'
-fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\243\200\346\237\245\347\233\256\345\275\225.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\243\200\346\237\245\347\233\256\345\275\225.sh"
deleted file mode 100644
index 7a1fe79b..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\243\200\346\237\245\347\233\256\345\275\225.sh"
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-# look before you leap
-
-if [ -d $HOME ]
-then
- echo "Your home directory exists"
- cd $HOME
- ls -a
-else
- echo "There is a problem with your HOME direcotry"
-fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\255\243\347\241\256\344\275\277\347\224\250\345\244\247\344\272\216\345\260\217\344\272\216\345\217\267.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\255\243\347\241\256\344\275\277\347\224\250\345\244\247\344\272\216\345\260\217\344\272\216\345\217\267.sh"
deleted file mode 100644
index 3cc68768..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\255\243\347\241\256\344\275\277\347\224\250\345\244\247\344\272\216\345\260\217\344\272\216\345\217\267.sh"
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-#正确使用大于小于号
-
-val1=baseball
-val2=hocky
-
-if [ $val1 \> $val2 ]
-then
- echo "$val1 is greater than $val2"
-else
- echo "$val1 is less than $val2"
-fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\350\247\243\345\206\263\350\257\273\345\217\226\345\210\227\350\241\250\344\270\255\347\232\204\345\244\215\346\235\202\345\200\274.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\350\247\243\345\206\263\350\257\273\345\217\226\345\210\227\350\241\250\344\270\255\347\232\204\345\244\215\346\235\202\345\200\274.sh"
deleted file mode 100644
index e5e442db..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\350\247\243\345\206\263\350\257\273\345\217\226\345\210\227\350\241\250\344\270\255\347\232\204\345\244\215\346\235\202\345\200\274.sh"
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-for test in I don\'t know if "this'll" work
-do
- echo "word:$test"
-done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\350\257\273\345\217\226\345\210\227\350\241\250\344\270\255\347\232\204\345\200\274.sh" "b/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\350\257\273\345\217\226\345\210\227\350\241\250\344\270\255\347\232\204\345\200\274.sh"
deleted file mode 100644
index 7063175b..00000000
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\350\257\273\345\217\226\345\210\227\350\241\250\344\270\255\347\232\204\345\200\274.sh"
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-# basic for command
-for test in Alabama Alaska Arizona
-do
- echo The next state is $test
-done
diff --git "a/codes/shell/\347\263\273\347\273\237\347\256\241\347\220\206/\346\216\247\345\210\266\350\277\234\347\250\213\346\234\215\345\212\241\345\231\250\346\211\247\350\241\214\346\214\207\344\273\244.sh" "b/codes/shell/\347\263\273\347\273\237\347\256\241\347\220\206/\346\216\247\345\210\266\350\277\234\347\250\213\346\234\215\345\212\241\345\231\250\346\211\247\350\241\214\346\214\207\344\273\244.sh"
new file mode 100644
index 00000000..c6a050e3
--- /dev/null
+++ "b/codes/shell/\347\263\273\347\273\237\347\256\241\347\220\206/\346\216\247\345\210\266\350\277\234\347\250\213\346\234\215\345\212\241\345\231\250\346\211\247\350\241\214\346\214\207\344\273\244.sh"
@@ -0,0 +1,30 @@
+#!/usr/bin/expect
+
+user="root"
+password="root"
+
+/usr/bin/expect << EOF
+set timeout 5
+spawn ssh -o "StrictHostKeyChecking no" ${user}@${host}
+expect {
+"yes/no)?" { send "yes\r"; exp_continue }
+"password:" { send "${password}\r" }
+}
+
+expect "root*"
+send "ssh-keygen -t rsa\r"
+expect "Enter file in which to save the key*"
+send "\r"
+
+expect {
+"(y/n)?" { send "n\r"; exp_continue }
+"Enter passphrase*" { send "\r"; exp_continue }
+"Enter same passphrase again:" { send "\r" }
+}
+
+expect "root*"
+send "df -h\r"
+expect "root*"
+send "exit\r"
+
+EOF
diff --git a/codes/shell/action/system/useradd.sh "b/codes/shell/\347\263\273\347\273\237\347\256\241\347\220\206/\347\263\273\347\273\237\347\224\250\346\210\267\347\256\241\347\220\206.sh"
similarity index 54%
rename from codes/shell/action/system/useradd.sh
rename to "codes/shell/\347\263\273\347\273\237\347\256\241\347\220\206/\347\263\273\347\273\237\347\224\250\346\210\267\347\256\241\347\220\206.sh"
index aefd2b7f..84111a11 100644
--- a/codes/shell/action/system/useradd.sh
+++ "b/codes/shell/\347\263\273\347\273\237\347\256\241\347\220\206/\347\263\273\347\273\237\347\224\250\346\210\267\347\256\241\347\220\206.sh"
@@ -1,5 +1,10 @@
#!/usr/bin/env bash
+###################################################################################
+# Linux 系统用户管理
+# @author: Zhang Peng
+###################################################################################
+
# 创建用户组
groupadd elk
# 创建新用户,-g elk 设置其用户组为 elk,-p elk 设置其密码为 elk
diff --git "a/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/lib.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/lib.sh"
new file mode 100644
index 00000000..ea297bbb
--- /dev/null
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/lib.sh"
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+add() {
+ echo $[ $1 + $2 ]
+}
+
+sub() {
+ echo $[ $1 - $2 ]
+}
+
+mul() {
+ echo $[ $1 * $2 ]
+}
+
+div() {
+ if [[ $2 -ne 0 ]]; then
+ echo $[ $1 / $2 ]
+ else
+ echo -1
+ fi
+}
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\273\216\345\207\275\346\225\260\350\277\224\345\233\236\346\225\260\347\273\204.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\273\216\345\207\275\346\225\260\350\277\224\345\233\236\346\225\260\347\273\204.sh"
similarity index 56%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\273\216\345\207\275\346\225\260\350\277\224\345\233\236\346\225\260\347\273\204.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\273\216\345\207\275\346\225\260\350\277\224\345\233\236\346\225\260\347\273\204.sh"
index 4425f558..1a9ddaf9 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\273\216\345\207\275\346\225\260\350\277\224\345\233\236\346\225\260\347\273\204.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\273\216\345\207\275\346\225\260\350\277\224\345\233\236\346\225\260\347\273\204.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# returning an array value
@@ -7,19 +7,19 @@ function arraydblr {
local newarray
local elements
local i
- origarry=(`echo "$@"`)
- newarray=(`echo "$@"`)
+ origarry=( `echo "$@"` )
+ newarray=( `echo "$@"` )
elements=$[ $# - 1 ]
- for (( i=0; i<=$elements; i++ ))
+ for (( i = 0; i <= $elements; i ++ ))
{
- newarray[$i]=$[ ${origarry[$i]} * 2 ]
+ newarray [ $i ] = $[ ${origarry[$i]} * 2 ]
}
echo ${newarray[*]}
}
-myarray=(1 2 3 4 5)
+myarray=( 1 2 3 4 5 )
echo "The original array is : ${myarray[*]}"
arg1=`echo ${myarray[*]}`
-result=(`arraydblr $arg1`)
+result=( `arraydblr $arg1` )
echo "The new array is : ${result[*]}"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250return\345\221\275\344\273\244.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250return\345\221\275\344\273\244.sh"
similarity index 89%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250return\345\221\275\344\273\244.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250return\345\221\275\344\273\244.sh"
index 412b86ac..b79d3411 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250return\345\221\275\344\273\244.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250return\345\221\275\344\273\244.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# using the return command in a function
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\205\250\345\261\200\345\217\230\351\207\217\345\270\246\346\235\245\347\232\204\351\227\256\351\242\230.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\205\250\345\261\200\345\217\230\351\207\217\345\270\246\346\235\245\347\232\204\351\227\256\351\242\230.sh"
similarity index 92%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\205\250\345\261\200\345\217\230\351\207\217\345\270\246\346\235\245\347\232\204\351\227\256\351\242\230.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\205\250\345\261\200\345\217\230\351\207\217\345\270\246\346\235\245\347\232\204\351\227\256\351\242\230.sh"
index 2758588f..aba7b8a2 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\205\250\345\261\200\345\217\230\351\207\217\345\270\246\346\235\245\347\232\204\351\227\256\351\242\230.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\205\250\345\261\200\345\217\230\351\207\217\345\270\246\346\235\245\347\232\204\351\227\256\351\242\230.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# demonstrating a bad use of variables
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\207\275\346\225\260\350\276\223\345\207\272.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\207\275\346\225\260\350\276\223\345\207\272.sh"
similarity index 75%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\207\275\346\225\260\350\276\223\345\207\272.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\207\275\346\225\260\350\276\223\345\207\272.sh"
index 4959d64f..1b3098ad 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\207\275\346\225\260\350\276\223\345\207\272.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\207\275\346\225\260\350\276\223\345\207\272.sh"
@@ -1,9 +1,10 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# using the echo to return a value
function db1 {
read -p "Enter a value:" value
- echo $[ $value*2 ]
+ echo $[ $value * 2 ]
}
result=`db1`
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\221\275\344\273\244\350\241\214\344\270\255\344\274\240\351\200\222\347\232\204\345\217\202\346\225\260.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\221\275\344\273\244\350\241\214\344\270\255\344\274\240\351\200\222\347\232\204\345\217\202\346\225\260.sh"
similarity index 92%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\221\275\344\273\244\350\241\214\344\270\255\344\274\240\351\200\222\347\232\204\345\217\202\346\225\260.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\221\275\344\273\244\350\241\214\344\270\255\344\274\240\351\200\222\347\232\204\345\217\202\346\225\260.sh"
index d31fe8b9..8020e32f 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\221\275\344\273\244\350\241\214\344\270\255\344\274\240\351\200\222\347\232\204\345\217\202\346\225\260.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\221\275\344\273\244\350\241\214\344\270\255\344\274\240\351\200\222\347\232\204\345\217\202\346\225\260.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# using a global variable to pass a value
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\261\200\351\203\250\345\217\230\351\207\217.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\261\200\351\203\250\345\217\230\351\207\217.sh"
similarity index 81%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\261\200\351\203\250\345\217\230\351\207\217.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\261\200\351\203\250\345\217\230\351\207\217.sh"
index 198bd810..5c03d1f3 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\261\200\351\203\250\345\217\230\351\207\217.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\261\200\351\203\250\345\217\230\351\207\217.sh"
@@ -1,9 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
# demonstrating the local keyword
function func1 {
- local temp=$[ $value +5 ]
+ local temp=$[ $value + 5 ]
result=$[ $temp * 2 ]
}
diff --git "a/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\272\223\345\207\275\346\225\260.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\272\223\345\207\275\346\225\260.sh"
new file mode 100644
index 00000000..c479bd8b
--- /dev/null
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\344\275\277\347\224\250\345\272\223\345\207\275\346\225\260.sh"
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+# 装载其它脚本
+source lib.sh
+
+echo "20 + 10 = $(add 20 10)"
+echo "20 - 10 = $(sub 20 10)"
+echo "20 * 10 = $(mul 20 10)"
+echo "20 / 10 = $(div 20 10)"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\205\250\345\261\200\345\217\230\351\207\217.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\205\250\345\261\200\345\217\230\351\207\217.sh"
similarity index 88%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\205\250\345\261\200\345\217\230\351\207\217.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\205\250\345\261\200\345\217\230\351\207\217.sh"
index c4c3d701..f1915c2d 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\205\250\345\261\200\345\217\230\351\207\217.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\205\250\345\261\200\345\217\230\351\207\217.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# using a global variable to pass a value
diff --git "a/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\205\245\345\217\202.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\205\245\345\217\202.sh"
new file mode 100644
index 00000000..57fd0f3d
--- /dev/null
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\205\245\345\217\202.sh"
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+x=0
+if [[ -n $1 ]]; then
+ echo "第一个参数为:$1"
+ x=$1
+else
+ echo "第一个参数为空"
+fi
+
+y=0
+if [[ -n $2 ]]; then
+ echo "第二个参数为:$2"
+ y=$2
+else
+ echo "第二个参数为空"
+fi
+
+paramsFunction() {
+ echo "函数第一个入参:$1"
+ echo "函数第二个入参:$2"
+}
+
+paramsFunction ${x} ${y}
diff --git a/codes/shell/demos/function/function-demo3.sh "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\205\245\345\217\2022.sh"
similarity index 50%
rename from codes/shell/demos/function/function-demo3.sh
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\205\245\345\217\2022.sh"
index 51dd54bb..1da51a04 100644
--- a/codes/shell/demos/function/function-demo3.sh
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\205\245\345\217\2022.sh"
@@ -1,24 +1,25 @@
#!/usr/bin/env bash
runner() {
- return 0
+ return 0
}
name=zp
-paramsFunction(){
- echo "函数第一个入参:$1"
- echo "函数第二个入参:$2"
- echo "传递到脚本的参数个数:$#"
- echo "所有参数:"
- printf "+ %s\n" "$*"
- echo "脚本运行的当前进程 ID 号:$$"
- echo "后台运行的最后一个进程的 ID 号:$!"
- echo "所有参数:"
- printf "+ %s\n" "$@"
- echo "Shell 使用的当前选项:$-"
- runner
- echo "runner 函数的返回值:$?"
+paramsFunction() {
+ echo "函数第一个入参:$1"
+ echo "函数第二个入参:$2"
+ echo "传递到脚本的参数个数:$#"
+ echo "所有参数:"
+ printf "+ %s\n" "$*"
+ echo "脚本运行的当前进程 ID 号:$$"
+ echo "后台运行的最后一个进程的 ID 号:$!"
+ echo "所有参数:"
+ printf "+ %s\n" "$@"
+ echo "Shell 使用的当前选项:$-"
+ runner
+ echo "runner 函数的返回值:$?"
}
+
paramsFunction 1 "abc" "hello, \"zp\""
# Output:
# 函数第一个入参:1
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\237\272\346\234\254\347\232\204\350\204\232\346\234\254\345\207\275\346\225\260.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\237\272\346\234\254\347\244\272\344\276\213.sh"
similarity index 83%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\237\272\346\234\254\347\232\204\350\204\232\346\234\254\345\207\275\346\225\260.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\237\272\346\234\254\347\244\272\344\276\213.sh"
index e881e977..e9b0ddff 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\237\272\346\234\254\347\232\204\350\204\232\346\234\254\345\207\275\346\225\260.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\237\272\346\234\254\347\244\272\344\276\213.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# using a function in script
@@ -10,7 +10,7 @@ count=1
while [ $count -le 5 ]
do
func1
- count=$[ $count+1 ]
+ count=$[ $count + 1 ]
done
echo "This is the end of the loop"
func1
diff --git "a/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\237\272\346\234\254\347\244\272\344\276\2132.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\237\272\346\234\254\347\244\272\344\276\2132.sh"
new file mode 100644
index 00000000..390ba308
--- /dev/null
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\345\237\272\346\234\254\347\244\272\344\276\2132.sh"
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+calc() {
+ PS3="choose the oper: "
+ select oper in "+" "-" "*" "/" # 生成操作符选择菜单
+ do
+ echo -n "enter first num: " && read x # 读取输入参数
+ echo -n "enter second num: " && read y # 读取输入参数
+ exec
+ case ${oper} in
+ "+")
+ return $((${x} + ${y}))
+ ;;
+ "-")
+ return $((${x} - ${y}))
+ ;;
+ "*")
+ return $((${x} * ${y}))
+ ;;
+ "/")
+ return $((${x} / ${y}))
+ ;;
+ *)
+ echo "${oper} is not support!"
+ return 0
+ ;;
+ esac
+ break
+ done
+}
+
+calc
+echo "the result is: $?" # $? 获取 calc 函数返回值
+# $ ./function-demo.sh
+# 1) +
+# 2) -
+# 3) *
+# 4) /
+# choose the oper: 3
+# enter first num: 10
+# enter second num: 10
+# the result is: 100
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\351\200\222\345\275\222.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\351\200\222\345\275\222.sh"
similarity index 83%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\351\200\222\345\275\222.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\351\200\222\345\275\222.sh"
index b362092d..7ee9c38c 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\351\200\222\345\275\222.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\207\275\346\225\260\351\200\222\345\275\222.sh"
@@ -1,11 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env bash
function factorial {
if [ $1 -eq 1 ]
then
echo 1
else
- local temp=$[ $1 -1 ]
+ local temp=$[ $1 - 1 ]
local result=`factorial $temp`
echo $[ $result * $1 ]
fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\234\250\345\207\275\346\225\260\344\270\255\344\275\277\347\224\250\345\217\202\346\225\260.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\234\250\345\207\275\346\225\260\344\270\255\344\275\277\347\224\250\345\217\202\346\225\260.sh"
similarity index 93%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\234\250\345\207\275\346\225\260\344\270\255\344\275\277\347\224\250\345\217\202\346\225\260.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\234\250\345\207\275\346\225\260\344\270\255\344\275\277\347\224\250\345\217\202\346\225\260.sh"
index 8ea4b1f7..01e59063 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\345\234\250\345\207\275\346\225\260\344\270\255\344\275\277\347\224\250\345\217\202\346\225\260.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\345\234\250\345\207\275\346\225\260\344\270\255\344\275\277\347\224\250\345\217\202\346\225\260.sh"
@@ -1,13 +1,13 @@
-#!/bin/bash
+#!/usr/bin/env bash
# passing parameters to a function
function addem {
if [ $# -eq 0 ] || [ $# -gt 2 ]
- then
+ then
echo -1
elif [ $# -eq 1 ]
- then
+ then
echo $[ $1 + $1 ]
else
echo $[ $1 + $2 ]
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\346\203\263\345\207\275\346\225\260\344\274\240\346\225\260\347\273\204\346\225\260\346\215\256.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\346\203\263\345\207\275\346\225\260\344\274\240\346\225\260\347\273\204\346\225\260\346\215\256.sh"
similarity index 86%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\346\203\263\345\207\275\346\225\260\344\274\240\346\225\260\347\273\204\346\225\260\346\215\256.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\346\203\263\345\207\275\346\225\260\344\274\240\346\225\260\347\273\204\346\225\260\346\215\256.sh"
index ab8b48d5..5f48c129 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\346\203\263\345\207\275\346\225\260\344\274\240\346\225\260\347\273\204\346\225\260\346\215\256.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\346\203\263\345\207\275\346\225\260\344\274\240\346\225\260\347\273\204\346\225\260\346\215\256.sh"
@@ -1,20 +1,20 @@
-#!/bin/bash
+#!/usr/bin/env bash
# trying to pass an array variable
function testit {
echo "The parameters are : $@"
-
+
#函数只会读取数组变量的第一个值
thisarray=$1
echo "The received array is ${thisarray[*]}"
local newarray
- newarray=(`echo "$@"`)
+ newarray=( `echo "$@"` )
echo "The new array value is : ${newarray[*]}"
}
-myarray=(1 2 3 4 5)
+myarray=( 1 2 3 4 5 )
echo "The original array is : ${myarray[*]}"
#将数组变量当成一个函数参数,函数只会去函数变量第一个值
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\347\264\257\345\212\240\346\225\260\347\273\204\344\270\255\347\232\204\345\200\274.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\347\264\257\345\212\240\346\225\260\347\273\204\344\270\255\347\232\204\345\200\274.sh"
similarity index 80%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\347\264\257\345\212\240\346\225\260\347\273\204\344\270\255\347\232\204\345\200\274.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\347\264\257\345\212\240\346\225\260\347\273\204\344\270\255\347\232\204\345\200\274.sh"
index 266f77c6..59fdd5f3 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\347\264\257\345\212\240\346\225\260\347\273\204\344\270\255\347\232\204\345\200\274.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\347\264\257\345\212\240\346\225\260\347\273\204\344\270\255\347\232\204\345\200\274.sh"
@@ -1,11 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env bash
#adding values in the array
function addarray {
local sum=0
local newarray
- newarray=(`echo "$@"`)
+ newarray=( `echo "$@"` )
for value in ${newarray[*]}
do
sum=$[ $sum + $value ]
@@ -13,7 +13,7 @@ function addarray {
echo $sum
}
-myarray=(1 2 3 4 5)
+myarray=( 1 2 3 4 5 )
echo "The original array is : ${myarray[*]}"
arg1=`echo ${myarray[*]}`
result=`addarray $arg1`
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\351\273\230\350\256\244\351\200\200\345\207\272\347\212\266\346\200\201\347\240\201.sh" "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\351\273\230\350\256\244\351\200\200\345\207\272\347\212\266\346\200\201\347\240\201.sh"
similarity index 96%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\351\273\230\350\256\244\351\200\200\345\207\272\347\212\266\346\200\201\347\240\201.sh"
rename to "codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\351\273\230\350\256\244\351\200\200\345\207\272\347\212\266\346\200\201\347\240\201.sh"
index bd2d5b4a..329f8f38 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\204\232\346\234\254\345\207\275\346\225\260/\351\273\230\350\256\244\351\200\200\345\207\272\347\212\266\346\200\201\347\240\201.sh"
+++ "b/codes/shell/\350\204\232\346\234\254\345\207\275\346\225\260/\351\273\230\350\256\244\351\200\200\345\207\272\347\212\266\346\200\201\347\240\201.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# testing the exit status of a function
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\344\275\277\347\224\250msgbox\351\203\250\344\273\266.sh" "b/codes/shell/\350\217\234\345\215\225/\344\275\277\347\224\250msgbox\351\203\250\344\273\266.sh"
similarity index 72%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\344\275\277\347\224\250msgbox\351\203\250\344\273\266.sh"
rename to "codes/shell/\350\217\234\345\215\225/\344\275\277\347\224\250msgbox\351\203\250\344\273\266.sh"
index c9aa8261..d7c1d354 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\344\275\277\347\224\250msgbox\351\203\250\344\273\266.sh"
+++ "b/codes/shell/\350\217\234\345\215\225/\344\275\277\347\224\250msgbox\351\203\250\344\273\266.sh"
@@ -1,3 +1,3 @@
-#!/bin/bash
+#!/usr/bin/env bash
dialog --title text --msgbox "This is a test" 10 20
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\344\275\277\347\224\250select\345\221\275\344\273\244.sh" "b/codes/shell/\350\217\234\345\215\225/\344\275\277\347\224\250select\345\221\275\344\273\244.sh"
similarity index 73%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\344\275\277\347\224\250select\345\221\275\344\273\244.sh"
rename to "codes/shell/\350\217\234\345\215\225/\344\275\277\347\224\250select\345\221\275\344\273\244.sh"
index 536a896c..ddcbee2c 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\344\275\277\347\224\250select\345\221\275\344\273\244.sh"
+++ "b/codes/shell/\350\217\234\345\215\225/\344\275\277\347\224\250select\345\221\275\344\273\244.sh"
@@ -1,8 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# using select in the menu
function diskspace {
- clear
+ clear
df -k
}
@@ -19,18 +20,18 @@ function menusage {
PS3="Enter option:"
select option in "Display disk space" "Display logged on users" "Display memory usage" "Exit program"
do
- case $option in
+case $option in
"Exit program")
- break;;
+ break ;;
"Display disk space")
- diskspace;;
+ diskspace ;;
"Display logged on users")
- whoseon;;
+ whoseon ;;
"Display memory usage")
- menusage;;
+ menusage ;;
*)
clear
- echo "Sorry, wrong selection";;
- esac
+ echo "Sorry, wrong selection" ;;
+esac
done
clear
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\344\275\277\347\224\250\350\204\232\346\234\254\350\217\234\345\215\225.sh" "b/codes/shell/\350\217\234\345\215\225/\344\275\277\347\224\250\350\204\232\346\234\254\350\217\234\345\215\225.sh"
similarity index 75%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\344\275\277\347\224\250\350\204\232\346\234\254\350\217\234\345\215\225.sh"
rename to "codes/shell/\350\217\234\345\215\225/\344\275\277\347\224\250\350\204\232\346\234\254\350\217\234\345\215\225.sh"
index 8634404d..7137078d 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\344\275\277\347\224\250\350\204\232\346\234\254\350\217\234\345\215\225.sh"
+++ "b/codes/shell/\350\217\234\345\215\225/\344\275\277\347\224\250\350\204\232\346\234\254\350\217\234\345\215\225.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
function menu {
clear
@@ -13,7 +13,7 @@ function menu {
}
function diskspace {
- clear
+ clear
df -k
}
@@ -31,17 +31,17 @@ while [ 1 ]
do
menu
case $option in
- 0)
- break;;
- 1)
- diskspace;;
- 2)
- whoseon;;
- 3)
- menusage;;
- *)
- clear
- echo "Sorry, wrong selection";;
+ 0)
+ break ;;
+ 1)
+ diskspace ;;
+ 2)
+ whoseon ;;
+ 3)
+ menusage ;;
+ *)
+ clear
+ echo "Sorry, wrong selection" ;;
esac
echo -en "\n\n\t\tHit any key to continue"
read -n 1 line
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250dialog\345\221\275\344\273\244.sh" "b/codes/shell/\350\217\234\345\215\225/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250dialog\345\221\275\344\273\244.sh"
similarity index 79%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250dialog\345\221\275\344\273\244.sh"
rename to "codes/shell/\350\217\234\345\215\225/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250dialog\345\221\275\344\273\244.sh"
index eceb20b1..d8c05d27 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\217\234\345\215\225/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250dialog\345\221\275\344\273\244.sh"
+++ "b/codes/shell/\350\217\234\345\215\225/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250dialog\345\221\275\344\273\244.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# using dialog to create a menu
@@ -31,16 +31,16 @@ do
selection=`cat $temp2`
case $selection in
- 1)
- diskspace;;
- 2)
- whoseon;;
- 3)
- menusage;;
- 0)
- break;;
- *)
- dialog --msgbox "Sorry,invalid selection" 10 30
+ 1)
+ diskspace ;;
+ 2)
+ whoseon ;;
+ 3)
+ menusage ;;
+ 0)
+ break ;;
+ *)
+ dialog --msgbox "Sorry,invalid selection" 10 30
esac
done
rm -f $temp 2> /dev/null
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/test" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/test"
similarity index 100%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/test"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/test"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/test1" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/test1"
similarity index 100%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/test1"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/test1"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\270\264\346\227\266\351\207\215\345\256\232\345\220\221.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\270\264\346\227\266\351\207\215\345\256\232\345\220\221.sh"
similarity index 84%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\270\264\346\227\266\351\207\215\345\256\232\345\220\221.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\270\264\346\227\266\351\207\215\345\256\232\345\220\221.sh"
index 4681abe6..3aa211f3 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\270\264\346\227\266\351\207\215\345\256\232\345\220\221.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\270\264\346\227\266\351\207\215\345\256\232\345\220\221.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# testing STDERR messages
echo "This is an error " >&2
diff --git "a/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts.sh"
new file mode 100644
index 00000000..4cb921e7
--- /dev/null
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts.sh"
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+# simple demonstration of the getopts command
+
+while getopts :ab:c opt
+do
+ case "$opt" in
+ a) echo "Found the -a option" ;;
+ b) echo "Found the -b option, with value $OPTARG" ;;
+ c) echo "Found the -c option" ;;
+ *) echo "Unknown option:$opt" ;;
+ esac
+done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts\345\244\204\347\220\206\351\200\211\351\241\271\345\222\214\345\217\202\346\225\260.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts\345\244\204\347\220\206\351\200\211\351\241\271\345\222\214\345\217\202\346\225\260.sh"
similarity index 50%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts\345\244\204\347\220\206\351\200\211\351\241\271\345\222\214\345\217\202\346\225\260.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts\345\244\204\347\220\206\351\200\211\351\241\271\345\222\214\345\217\202\346\225\260.sh"
index 732ac69e..ef63a4d8 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts\345\244\204\347\220\206\351\200\211\351\241\271\345\222\214\345\217\202\346\225\260.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopts\345\244\204\347\220\206\351\200\211\351\241\271\345\222\214\345\217\202\346\225\260.sh"
@@ -1,14 +1,15 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# processing options and parameters with getopts
while getopts :ab:cd opt
do
case "$opt" in
- a) echo "Found the -a option";;
- b) echo "Found the -b option,with value $OPTARG";;
- c) echo "Found the -c option";;
- d) echo "Found the -d option";;
- *) echo "Unknown option: $opt";;
+ a) echo "Found the -a option" ;;
+ b) echo "Found the -b option,with value $OPTARG" ;;
+ c) echo "Found the -c option" ;;
+ d) echo "Found the -d option" ;;
+ *) echo "Unknown option: $opt" ;;
esac
done
shift $[ $OPTIND - 1 ]
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopt\345\221\275\344\273\244.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopt\345\221\275\344\273\244.sh"
similarity index 62%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopt\345\221\275\344\273\244.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopt\345\221\275\344\273\244.sh"
index 55c98677..0004309a 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopt\345\221\275\344\273\244.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250getopt\345\221\275\344\273\244.sh"
@@ -1,18 +1,19 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#extracting command line options and values with getopt
# getopt command is not goot at dealing with space,we can use getopts
set -- `getopt -q ab:c "$@"`
while [ -n "$1" ]
do
case "$1" in
- -a) echo "Found the -a option";;
- -b) param="$2"
+ -a) echo "Found the -a option" ;;
+ -b) param="$2"
echo "Found the -b option,with parameter value $param"
- shift;;
- -c) echo "Found the -c option";;
- --) shift
- break;;
- *) echo "$1 is not an option";;
+ shift ;;
+ -c) echo "Found the -c option" ;;
+ --) shift
+ break ;;
+ *) echo "$1 is not an option" ;;
esac
shift
done
@@ -21,5 +22,5 @@ count=1
for param in "$@"
do
echo "Parameter #$count: $param"
- count=$[ $count+1 ]
+ count=$[ $count + 1 ]
done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250shift\345\221\275\344\273\244.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250shift\345\221\275\344\273\244.sh"
similarity index 84%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250shift\345\221\275\344\273\244.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250shift\345\221\275\344\273\244.sh"
index 11877cff..c580f8e6 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250shift\345\221\275\344\273\244.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\344\275\277\347\224\250shift\345\221\275\344\273\244.sh"
@@ -1,11 +1,12 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# shift n 移动变量
count=1
while [ -n "$1" ]
do
echo "Parameter #$count = $1"
- count=$[ $count+1 ]
+ count=$[ $count + 1 ]
shift
done
diff --git "a/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\205\215\345\257\206\347\240\201\344\274\240\350\276\223.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\205\215\345\257\206\347\240\201\344\274\240\350\276\223.sh"
new file mode 100644
index 00000000..30264bda
--- /dev/null
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\205\215\345\257\206\347\240\201\344\274\240\350\276\223.sh"
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+# ------------------------------------------------------------------------------
+# 免密码传输
+# @author Zhang Peng
+# @since 2020/4/8
+# ------------------------------------------------------------------------------
+
+REMOTE_HOST=192.168.0.2
+
+# 如果本机没有公私钥对,可以执行以下命令生成 ssh 公私钥对
+#ssh-keygen -t rsa
+
+# 服务器 A 上执行以下命令
+scp ~/.ssh/id_rsa.pub root@${REMOTE_HOST}:~/.ssh/id_rsa.pub.tmp
+
+# 服务器 B 上执行以下命令
+cat ~/.ssh/id_rsa.pub.tmp >> ~/.ssh/authorized_keys
+rm ~/.ssh/id_rsa.pub.tmp
diff --git "a/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\206\347\246\273\345\217\202\346\225\260\345\222\214\351\200\211\351\241\271.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\206\347\246\273\345\217\202\346\225\260\345\222\214\351\200\211\351\241\271.sh"
new file mode 100644
index 00000000..51c0d5be
--- /dev/null
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\206\347\246\273\345\217\202\346\225\260\345\222\214\351\200\211\351\241\271.sh"
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+#extracting options and parameters
+
+while [ -n "$1" ]
+do
+ case "$1" in
+ -a) echo "Found the -a option" ;;
+ -b) echo "Found the -b option" ;;
+ -c) echo "Found the -c option" ;;
+ --) shift
+ break ;;
+ *) echo "$1 is not an option" ;;
+ esac
+ shift
+done
+
+count=1
+for param in $@
+do
+ echo "Parameter #$count: $param"
+ count=$[ $count + 1 ]
+done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\227\345\207\272\345\275\223\345\211\215\350\204\232\346\234\254\346\211\223\345\274\200\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\227\345\207\272\345\275\223\345\211\215\350\204\232\346\234\254\346\211\223\345\274\200\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
similarity index 55%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\227\345\207\272\345\275\223\345\211\215\350\204\232\346\234\254\346\211\223\345\274\200\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\227\345\207\272\345\275\223\345\211\215\350\204\232\346\234\254\346\211\223\345\274\200\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
index 417bfa41..f4b44acd 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\227\345\207\272\345\275\223\345\211\215\350\204\232\346\234\254\346\211\223\345\274\200\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\227\345\207\272\345\275\223\345\211\215\350\204\232\346\234\254\346\211\223\345\274\200\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
@@ -1,10 +1,10 @@
-#!/bin/bash
+#!/usr/bin/env bash
# testing lsof with file descriptors
-exec 3>test
-exec 6>test
-exec 7 test
+exec 6> test
+exec 7< test
lsof -a -p $$ -d0,1,2,3,6,7
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\344\273\216\344\273\245\351\207\215\345\256\232\345\220\221\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246\344\270\255\346\201\242\345\244\215.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\344\273\216\344\273\245\351\207\215\345\256\232\345\220\221\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246\344\270\255\346\201\242\345\244\215.sh"
similarity index 84%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\344\273\216\344\273\245\351\207\215\345\256\232\345\220\221\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246\344\270\255\346\201\242\345\244\215.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\344\273\216\344\273\245\351\207\215\345\256\232\345\220\221\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246\344\270\255\346\201\242\345\244\215.sh"
index 0face232..36dae530 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\344\273\216\344\273\245\351\207\215\345\256\232\345\220\221\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246\344\270\255\346\201\242\345\244\215.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\344\273\216\344\273\245\351\207\215\345\256\232\345\220\221\347\232\204\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246\344\270\255\346\201\242\345\244\215.sh"
@@ -1,9 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
#storing STDOUT, then coming back to it
exec 3>&1
-exec 1>test
+exec 1> test
echo "This should store in output file"
echo "along with this line"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\205\263\351\227\255\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\205\263\351\227\255\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
similarity index 81%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\205\263\351\227\255\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\205\263\351\227\255\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
index 154e2bf7..dc0ec40b 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\205\263\351\227\255\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\205\263\351\227\255\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
@@ -1,7 +1,8 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# testing closing file descriptors
-exec 3>test
+exec 3> test
echo "This is a test line of data" >&3
# closing file descriptor
@@ -12,5 +13,5 @@ echo "This won't work" >&3
cat test
#覆盖前一个test文件
-exec 3>test
+exec 3> test
echo "This'll be bad" >&3
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\257\273\345\206\231\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\257\273\345\206\231\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
similarity index 85%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\257\273\345\206\231\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\257\273\345\206\231\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
index 53b76454..4ad4b6ea 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\257\273\345\206\231\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\257\273\345\206\231\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# testing inpiut/output file descriptor
exec 3<> test
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\276\223\345\205\245\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\276\223\345\205\245\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
similarity index 64%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\276\223\345\205\245\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\276\223\345\205\245\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
index c47be1b1..8aadb6d8 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\276\223\345\205\245\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\210\233\345\273\272\350\207\252\345\267\261\347\232\204\351\207\215\345\256\232\345\220\221/\345\210\233\345\273\272\350\276\223\345\205\245\346\226\207\344\273\266\346\217\217\350\277\260\347\254\246.sh"
@@ -1,22 +1,23 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# redirecting input file descriptors
exec 3>&1
echo "This is the 3 file descriptor" >&3
exec 6>&0
-exec 0test
+exec 3> test
echo "This should display on the monitor"
echo "and this should be stored in the file" >&3
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\217\202\346\225\260\350\256\241\346\225\260.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\217\202\346\225\260\350\256\241\346\225\260.sh"
similarity index 90%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\217\202\346\225\260\350\256\241\346\225\260.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\217\202\346\225\260\350\256\241\346\225\260.sh"
index 65673e87..866e2b25 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\217\202\346\225\260\350\256\241\346\225\260.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\217\202\346\225\260\350\256\241\346\225\260.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# getting the number of parameters
echo There were $# parameters supplied
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250\351\207\215\345\256\232\345\220\221\350\276\223\345\205\245.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250\351\207\215\345\256\232\345\220\221\350\276\223\345\205\245.sh"
similarity index 78%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250\351\207\215\345\256\232\345\220\221\350\276\223\345\205\245.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250\351\207\215\345\256\232\345\220\221\350\276\223\345\205\245.sh"
index c3105fe0..0ad827ac 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250\351\207\215\345\256\232\345\220\221\350\276\223\345\205\245.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\234\250\350\204\232\346\234\254\344\270\255\344\275\277\347\224\250\351\207\215\345\256\232\345\220\221\350\276\223\345\205\245.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# redirecting the inpiut
# 从test中读取数据,而不是从STDIN中读取数据
@@ -7,6 +8,6 @@ count=1
while read line
do
echo "Line #$count : $line "
- count=$[ $count +1 ]
+ count=$[ $count + 1 ]
done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\345\270\246\345\200\274\347\232\204\351\200\211\351\241\271.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\345\270\246\345\200\274\347\232\204\351\200\211\351\241\271.sh"
similarity index 57%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\345\270\246\345\200\274\347\232\204\351\200\211\351\241\271.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\345\270\246\345\200\274\347\232\204\351\200\211\351\241\271.sh"
index b8cc6315..3fbd65da 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\345\270\246\345\200\274\347\232\204\351\200\211\351\241\271.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\345\270\246\345\200\274\347\232\204\351\200\211\351\241\271.sh"
@@ -1,18 +1,18 @@
-#!/bin/bash
+#!/usr/bin/env bash
# extracting command line options and values
while [ -n "$1" ]
-do
+do
case "$1" in
- -a) echo "Found the -a option";;
- -b) param="$2"
+ -a) echo "Found the -a option" ;;
+ -b) param="$2"
echo "Found the -b option, with parameter value $param"
- shift;;
- -c) echo "Found the -c option";;
- --) shift
- break;;
- *) echo "$1 is not an option";;
+ shift ;;
+ -c) echo "Found the -c option" ;;
+ --) shift
+ break ;;
+ *) echo "$1 is not an option" ;;
esac
shift
done
diff --git "a/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\347\256\200\345\215\225\351\200\211\351\241\271.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\347\256\200\345\215\225\351\200\211\351\241\271.sh"
new file mode 100644
index 00000000..f5e5de35
--- /dev/null
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\244\204\347\220\206\347\256\200\345\215\225\351\200\211\351\241\271.sh"
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+# extracting command line options as parameters
+
+while [ -n "$1" ]
+do
+ case "$1" in
+ -a) echo "Found the -a option" ;;
+ -b) echo "Found the -b optins" ;;
+ -c) echo "Found the -c optins" ;;
+ *) echo "$1 is not a valid options" ;;
+ esac
+ shift
+done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\277\253\351\200\237\346\270\205\351\231\244\346\226\207\344\273\266\346\210\226\346\227\245\345\277\227.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\277\253\351\200\237\346\270\205\351\231\244\346\226\207\344\273\266\346\210\226\346\227\245\345\277\227.sh"
similarity index 68%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\277\253\351\200\237\346\270\205\351\231\244\346\226\207\344\273\266\346\210\226\346\227\245\345\277\227.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\277\253\351\200\237\346\270\205\351\231\244\346\226\207\344\273\266\346\210\226\346\227\245\345\277\227.sh"
index bd9fa647..b7b1f749 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\277\253\351\200\237\346\270\205\351\231\244\346\226\207\344\273\266\346\210\226\346\227\245\345\277\227.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\345\277\253\351\200\237\346\270\205\351\231\244\346\226\207\344\273\266\346\210\226\346\227\245\345\277\227.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# 清除日志
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\212\223\345\217\226\346\211\200\346\234\211\346\225\260\346\215\256.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\212\223\345\217\226\346\211\200\346\234\211\346\225\260\346\215\256.sh"
similarity index 71%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\212\223\345\217\226\346\211\200\346\234\211\346\225\260\346\215\256.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\212\223\345\217\226\346\211\200\346\234\211\346\225\260\346\215\256.sh"
index a93ccf06..fb7fa738 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\212\223\345\217\226\346\211\200\346\234\211\346\225\260\346\215\256.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\212\223\345\217\226\346\211\200\346\234\211\346\225\260\346\215\256.sh"
@@ -1,16 +1,17 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# testing $* and $@
count=1
for param in "$*"
do
echo "\$* Parameter #$count = $param"
- count=$[ $count+1 ]
+ count=$[ $count + 1 ]
done
count=1
for param in "$@"
do
echo "\$@ Paramenter #$count = $param"
- count=$[ $count+1 ]
+ count=$[ $count + 1 ]
done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\260\270\344\271\205\351\207\215\345\256\232\345\220\221.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\260\270\344\271\205\351\207\215\345\256\232\345\220\221.sh"
similarity index 87%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\260\270\344\271\205\351\207\215\345\256\232\345\220\221.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\260\270\344\271\205\351\207\215\345\256\232\345\220\221.sh"
index d03a3bd7..82e51e30 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\260\270\344\271\205\351\207\215\345\256\232\345\220\221.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\260\270\344\271\205\351\207\215\345\256\232\345\220\221.sh"
@@ -1,14 +1,15 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# testing STDERR messages
# redirecting all to a file
# 脚本执行期间,用exec命令告诉shell重定向某个特定文件描述符
-exec 2>test
+exec 2> test
ls badtest
echo "This is test of redirecting all output"
echo "from a script to another file"
-exec 1>test1
+exec 1> test1
echo "This is the end of the script"
echo "but this should go to the testerror file" >&2
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\265\213\350\257\225.txt" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\265\213\350\257\225.txt"
similarity index 100%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\265\213\350\257\225.txt"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\346\265\213\350\257\225.txt"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\216\267\345\217\226\347\224\250\346\210\267\350\276\223\345\205\245.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\216\267\345\217\226\347\224\250\346\210\267\350\276\223\345\205\245.sh"
similarity index 90%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\216\267\345\217\226\347\224\250\346\210\267\350\276\223\345\205\245.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\216\267\345\217\226\347\224\250\346\210\267\350\276\223\345\205\245.sh"
index 4e361863..24fbde30 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\216\267\345\217\226\347\224\250\346\210\267\350\276\223\345\205\245.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\216\267\345\217\226\347\224\250\346\210\267\350\276\223\345\205\245.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# testing the reading command
@@ -17,7 +17,7 @@ echo "Checking data for $last. $first..."
#如果不指定变量,read命令就会把它收到的任何数据都放到特殊环境变量REPLY中
read -p "Enter a number:"
factorial=1
-for (( count=1; count<=$REPLY; count++))
+for (( count = 1; count <= $REPLY; count ++ ))
do
factorial=$[ $factorial * $count ]
done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\256\260\345\275\225\344\277\241\346\201\257.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\256\260\345\275\225\344\277\241\346\201\257.sh"
similarity index 93%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\256\260\345\275\225\344\277\241\346\201\257.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\256\260\345\275\225\344\277\241\346\201\257.sh"
index 84d31dbc..907d7e4f 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\256\260\345\275\225\344\277\241\346\201\257.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\256\260\345\275\225\344\277\241\346\201\257.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# using the tee command for logging
#将输入一边发送到STDOUT,一边发送到日志文件
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\217\202\346\225\260.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\217\202\346\225\260.sh"
similarity index 66%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\217\202\346\225\260.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\217\202\346\225\260.sh"
index 1a37a7cf..be23518b 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\217\202\346\225\260.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\217\202\346\225\260.sh"
@@ -1,9 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
# using one command line parameter
factorial=1
-for (( number = 1; number <= $1; number++))
+for (( number = 1; number <= $1; number ++ ))
do
factorial=$[ $factorial * $number ]
done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\244\232\344\270\252\345\221\275\344\273\244\350\241\214\345\217\202\346\225\260.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\244\232\344\270\252\345\221\275\344\273\244\350\241\214\345\217\202\346\225\260.sh"
similarity index 88%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\244\232\344\270\252\345\221\275\344\273\244\350\241\214\345\217\202\346\225\260.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\244\232\344\270\252\345\221\275\344\273\244\350\241\214\345\217\202\346\225\260.sh"
index 6d2efcf6..2f2f6d04 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\244\232\344\270\252\345\221\275\344\273\244\350\241\214\345\217\202\346\225\260.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\345\244\232\344\270\252\345\221\275\344\273\244\350\241\214\345\217\202\346\225\260.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# handing lots of parameters
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\347\250\213\345\272\217\345\220\215.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\347\250\213\345\272\217\345\220\215.sh"
similarity index 91%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\347\250\213\345\272\217\345\220\215.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\347\250\213\345\272\217\345\220\215.sh"
index f148da03..36941cff 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\347\250\213\345\272\217\345\220\215.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\347\250\213\345\272\217\345\220\215.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# testing the $0 parameter
echo The command entered is $0
diff --git a/codes/shell/action/oper/input.sh "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\351\200\211\346\213\251\345\217\202\346\225\260.sh"
similarity index 74%
rename from codes/shell/action/oper/input.sh
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\351\200\211\346\213\251\345\217\202\346\225\260.sh"
index 29ad9182..2e2e38f8 100644
--- a/codes/shell/action/oper/input.sh
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\257\273\345\217\226\351\200\211\346\213\251\345\217\202\346\225\260.sh"
@@ -7,19 +7,19 @@
################### 读取脚本输入参数并校验 ###################
declare -a serial
-serial=(start stop restart)
+serial=( start stop restart )
echo -n "请选择操作(可选值:start|stop|restart):"
-read oper
+read oper
if ! echo ${serial[@]} | grep -q ${oper}; then
- echo "请选择正确操作(可选值:start|stop|restart)"
- exit 1
+ echo "请选择正确操作(可选值:start|stop|restart)"
+ exit 1
fi
declare -a serial2
-serial2=(dev test prod)
+serial2=( dev test prod )
echo -n "请选择运行环境(可选值:dev|test|prod):"
-read profile
+read profile
if ! echo ${serial2[@]} | grep -q ${profile}; then
- echo "请选择正确运行环境(可选值:dev|test|prod)"
- exit 1
+ echo "请选择正确运行环境(可选值:dev|test|prod)"
+ exit 1
fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\266\205\346\227\266\345\222\214\350\276\223\345\205\245\350\256\241\346\225\260.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\266\205\346\227\266\345\222\214\350\276\223\345\205\245\350\256\241\346\225\260.sh"
similarity index 67%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\266\205\346\227\266\345\222\214\350\276\223\345\205\245\350\256\241\346\225\260.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\266\205\346\227\266\345\222\214\350\276\223\345\205\245\350\256\241\346\225\260.sh"
index 7dc83875..024c4a66 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\266\205\346\227\266\345\222\214\350\276\223\345\205\245\350\256\241\346\225\260.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\350\266\205\346\227\266\345\222\214\350\276\223\345\205\245\350\256\241\346\225\260.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# timing the data entry
if read -t 5 -p "Please enter your name:" name
@@ -10,12 +11,12 @@ else
#输入计数 -n1
read -n1 -p "Do you want to continue [Y/N]?" answer
case $answer in
- Y | y) echo
- echo "Fine, continue on...";;
- N | n) echo
- echo "OK,goodbye";;
- *) echo
- echo "OK, wrong, goodbye"
+ Y | y) echo
+ echo "Fine, continue on..." ;;
+ N | n) echo
+ echo "OK,goodbye" ;;
+ *) echo
+ echo "OK, wrong, goodbye"
esac
echo "Sorry, this is the end of the script"
fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\351\232\220\350\227\217\346\226\271\345\274\217\350\257\273\345\217\226\346\225\260\346\215\256.sh" "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\351\232\220\350\227\217\346\226\271\345\274\217\350\257\273\345\217\226\346\225\260\346\215\256.sh"
similarity index 88%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\351\232\220\350\227\217\346\226\271\345\274\217\350\257\273\345\217\226\346\225\260\346\215\256.sh"
rename to "codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\351\232\220\350\227\217\346\226\271\345\274\217\350\257\273\345\217\226\346\225\260\346\215\256.sh"
index 1299be24..27869813 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\351\232\220\350\227\217\346\226\271\345\274\217\350\257\273\345\217\226\346\225\260\346\215\256.sh"
+++ "b/codes/shell/\350\276\223\345\205\245\345\222\214\350\276\223\345\207\272/\351\232\220\350\227\217\346\226\271\345\274\217\350\257\273\345\217\226\346\225\260\346\215\256.sh"
@@ -1,8 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# hiding input data from monitor
read -s -p "Please enter your password: " pass
#添加了-s选项之后,不会自动换行,不添加-s 会自动换行
-echo
+echo
echo "Is your password really $pass?"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh" "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
similarity index 96%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
rename to "codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
index 85059456..4c86de9a 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
+++ "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#
# Capture_Stats - Gather System Performance Statistics
#
diff --git a/codes/shell/demos/debug-demo.sh "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\345\274\200\345\220\257debug\346\250\241\345\274\217.sh"
similarity index 77%
rename from codes/shell/demos/debug-demo.sh
rename to "codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\345\274\200\345\220\257debug\346\250\241\345\274\217.sh"
index 37afac64..0f75ff11 100644
--- a/codes/shell/demos/debug-demo.sh
+++ "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\345\274\200\345\220\257debug\346\250\241\345\274\217.sh"
@@ -2,8 +2,8 @@
# 开启 debug
set -x
-for (( i = 0; i < 3; i++ )); do
- printf ${i}
+for (( i = 0; i < 3; i ++ )); do
+ printf ${i}
done
# 关闭 debug
set +x
@@ -21,6 +21,8 @@ set +x
# + (( i < 3 ))
# + set +x
-for i in {1..5}; do printf ${i}; done
+for i in {1..5}; do
+ printf ${i};
+done
printf "\n"
# Output: 12345
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\346\237\245\347\234\213uptime\350\216\267\345\217\226\345\234\250\347\272\277\347\224\250\346\210\267\346\225\260.sh" "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\346\237\245\347\234\213uptime\350\216\267\345\217\226\345\234\250\347\272\277\347\224\250\346\210\267\346\225\260.sh"
similarity index 70%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\346\237\245\347\234\213uptime\350\216\267\345\217\226\345\234\250\347\272\277\347\224\250\346\210\267\346\225\260.sh"
rename to "codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\346\237\245\347\234\213uptime\350\216\267\345\217\226\345\234\250\347\272\277\347\224\250\346\210\267\346\225\260.sh"
index 07ba5ba9..2ac01f72 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\346\237\245\347\234\213uptime\350\216\267\345\217\226\345\234\250\347\272\277\347\224\250\346\210\267\346\225\260.sh"
+++ "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\346\237\245\347\234\213uptime\350\216\267\345\217\226\345\234\250\347\272\277\347\224\250\346\210\267\346\225\260.sh"
@@ -1,3 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#
uptime | sed 's/user.*$//' | gawk '{print $NF}'
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\347\224\237\346\210\220\346\212\245\345\221\212\350\204\232\346\234\254-\345\237\272\344\272\216\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh" "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\347\224\237\346\210\220\346\212\245\345\221\212\350\204\232\346\234\254-\345\237\272\344\272\216\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
similarity index 98%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\347\224\237\346\210\220\346\212\245\345\221\212\350\204\232\346\234\254-\345\237\272\344\272\216\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
rename to "codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\347\224\237\346\210\220\346\212\245\345\221\212\350\204\232\346\234\254-\345\237\272\344\272\216\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
index 35fce817..da989496 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\347\224\237\346\210\220\346\212\245\345\221\212\350\204\232\346\234\254-\345\237\272\344\272\216\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
+++ "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\347\224\237\346\210\220\346\212\245\345\221\212\350\204\232\346\234\254-\345\237\272\344\272\216\345\210\233\345\273\272\346\215\225\346\215\211\350\204\232\346\234\254.sh"
@@ -1,9 +1,10 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#
# Report_Stats - Generates Rpt from Captured Perf Stats
#
############################################################
-#
+#
# Set Script Variables
#
REPORT_FILE=/home/tiandi/Documents/capstats.csv
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\347\263\273\347\273\237\345\277\253\347\205\247\346\212\245\345\221\212.sh" "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\347\263\273\347\273\237\345\277\253\347\205\247\346\212\245\345\221\212.sh"
similarity index 89%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\347\263\273\347\273\237\345\277\253\347\205\247\346\212\245\345\221\212.sh"
rename to "codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\347\263\273\347\273\237\345\277\253\347\205\247\346\212\245\345\221\212.sh"
index 8614a1c7..f3ad3c25 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\347\263\273\347\273\237\345\277\253\347\205\247\346\212\245\345\221\212.sh"
+++ "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\347\263\273\347\273\237\345\277\253\347\205\247\346\212\245\345\221\212.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#
# Snapshot_Stats - produces a report for system stats
#
@@ -16,9 +17,9 @@ REPORT=/home/tiandi/Documents/Snapshot_Stats_$DATE.rpt
#
# Create Report File
#
-exec 3>&1 # Save file descriptor
+exec 3>&1 # Save file descriptor
#
-exec 1> $REPORT # direct output to rpt file
+exec 1> $REPORT # direct output to rpt file
#
###################################################
#
@@ -44,7 +45,7 @@ uptime | sed -n '/,/s/,/ /gp' | gawk '{if($4 == "days" || $4 == "day") {print $2
#2) Gather Disk Usage Statistics
#
echo
-for DISK in $DISK_TO_MONITOR # loop to check disk space
+for DISK in $DISK_TO_MONITOR # loop to check disk space
do
echo -e "$DISK usage: \c"
df -h $DISK | sed -n '/% \//p' | gawk '{ print $5 }'
@@ -79,7 +80,7 @@ echo
#
# Restore File Descriptor & Mail Report
#
-exec 1>&3 # Restore output to STDOUT
+exec 1>&3 # Restore output to STDOUT
#
#$MAIL -a $REPORT -s "System Sstatistics Report for $DATE"
#-- $MAIL_TO < /dev/null
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\350\276\223\345\207\272\351\242\234\350\211\262.sh" "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\350\276\223\345\207\272\351\242\234\350\211\262.sh"
similarity index 100%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\350\276\223\345\207\272\351\242\234\350\211\262.sh"
rename to "codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\350\276\223\345\207\272\351\242\234\350\211\262.sh"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\351\227\256\351\242\230\350\267\237\350\270\252\346\225\260\346\215\256\345\272\223/Update_Problem.sh" "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\351\227\256\351\242\230\350\267\237\350\270\252\346\225\260\346\215\256\345\272\223/Update_Problem.sh"
similarity index 76%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\351\227\256\351\242\230\350\267\237\350\270\252\346\225\260\346\215\256\345\272\223/Update_Problem.sh"
rename to "codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\351\227\256\351\242\230\350\267\237\350\270\252\346\225\260\346\215\256\345\272\223/Update_Problem.sh"
index a935ad10..602547aa 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\350\277\233\351\230\266\350\204\232\346\234\254/\351\227\256\351\242\230\350\267\237\350\270\252\346\225\260\346\215\256\345\272\223/Update_Problem.sh"
+++ "b/codes/shell/\350\277\233\351\230\266\350\204\232\346\234\254/\351\227\256\351\242\230\350\267\237\350\270\252\346\225\260\346\215\256\345\272\223/Update_Problem.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#
# Update_Problem - updates problem record in database
#
@@ -12,21 +13,22 @@ MYSQL=`which mysql`" Problem_Trek -u root"
#
# Obtain Record Id
#
-if [ $# -eq 0 ] # Check if id number was passed
-then # If not passed ask for it
-#
-# Check if any unfinished records exist.
+if [ $# -eq 0 ] # Check if id number was passed
+then
+ # If not passed ask for it
+ #
+ # Check if any unfinished records exist.
RECORDS_EXIST=`$MYSQL -Bse 'SELECT id_number FROM problem_logger where fixed_date="0000-00-00" OR prob_solutions=""'`
-#
+ #
if [ "$RECORDS_EXIST" != "" ]
- then
+ then
echo
echo "The following record(s) need updating..."
- $MYSQL < ${y} ]]; then
- echo "${x} > ${y}"
+ echo "${x} > ${y}"
elif [[ ${x} < ${y} ]]; then
- echo "${x} < ${y}"
+ echo "${x} < ${y}"
else
- echo "${x} = ${y}"
+ echo "${x} = ${y}"
fi
# Output: 10 < 20
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/output.txt" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/output.txt"
similarity index 100%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/output.txt"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/output.txt"
diff --git a/codes/shell/demos/statement/select-demo.sh "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/select\350\217\234\345\215\225\347\244\272\344\276\213.sh"
similarity index 59%
rename from codes/shell/demos/statement/select-demo.sh
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/select\350\217\234\345\215\225\347\244\272\344\276\213.sh"
index 956ac8f3..ef786daf 100644
--- a/codes/shell/demos/statement/select-demo.sh
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/select\350\217\234\345\215\225\347\244\272\344\276\213.sh"
@@ -5,10 +5,10 @@ select ITEM in bower npm gem pip
do
echo -n "Enter the package name: " && read PACKAGE
case ${ITEM} in
- bower) bower install ${PACKAGE} ;;
- npm) npm install ${PACKAGE} ;;
- gem) gem install ${PACKAGE} ;;
- pip) pip install ${PACKAGE} ;;
+ bower) bower install ${PACKAGE} ;;
+ npm) npm install ${PACKAGE} ;;
+ gem) gem install ${PACKAGE} ;;
+ pip) pip install ${PACKAGE} ;;
esac
break # 避免无限循环
done
diff --git "a/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/until\347\244\272\344\276\213.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/until\347\244\272\344\276\213.sh"
new file mode 100644
index 00000000..97070802
--- /dev/null
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/until\347\244\272\344\276\213.sh"
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+x=0
+until [[ ${x} -ge 5 ]]; do
+ echo ${x}
+ x=`expr ${x} + 1`
+done
+# Output:
+# 0
+# 1
+# 2
+# 3
+# 4
+
+x=0
+until echo $x
+[[ $x -ge 5 ]]
+do
+ x=$[ $x + 1 ]
+done
+# Output:
+# 0
+# 1
+# 2
+# 3
+# 4
+# 5
diff --git "a/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/while\345\276\252\347\216\257\347\244\272\344\276\213.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/while\345\276\252\347\216\257\347\244\272\344\276\213.sh"
new file mode 100644
index 00000000..30e73f0c
--- /dev/null
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/while\345\276\252\347\216\257\347\244\272\344\276\213.sh"
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+
+################### while 循环输出 0 ~ 9 的平方数 ###################
+x=0
+while [[ ${x} -lt 10 ]]; do
+ echo $((x * x))
+ x=$((x + 1))
+done
+# Output:
+# 0
+# 1
+# 4
+# 9
+# 16
+# 25
+# 36
+# 49
+# 64
+# 81
+
+################### while 循环输出 0 ~ 9 ###################
+x=0
+while echo ${x}
+[[ ${x} -lt 9 ]]
+do
+ x=$((x + 1))
+done
+# Output:
+# 0
+# 1
+# 2
+# 3
+# 4
+# 5
+# 6
+# 7
+# 8
+# 9
+
+################### while 循环嵌套 for 循环 ###################
+x=5
+while [[ $x -ge 0 ]]
+do
+ echo "Outer loop: $x"
+ for (( y = 1; $y < 3; y ++ ))
+ do
+ z=$[ $x * $y ]
+ echo "Inner loop: $x * $y = $z"
+ done
+ x=$[ $x - 1 ]
+done
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\273\216\345\221\275\344\273\244\350\257\273\345\217\226\345\200\274.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\273\216\345\221\275\344\273\244\350\257\273\345\217\226\345\200\274.sh"
similarity index 93%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\273\216\345\221\275\344\273\244\350\257\273\345\217\226\345\200\274.sh"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\273\216\345\221\275\344\273\244\350\257\273\345\217\226\345\200\274.sh"
index a5e52c41..3f8c4969 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\273\216\345\221\275\344\273\244\350\257\273\345\217\226\345\200\274.sh"
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\273\216\345\221\275\344\273\244\350\257\273\345\217\226\345\200\274.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#reading values from a file
file="state"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\345\234\206\346\213\254\345\217\267.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\345\234\206\346\213\254\345\217\267.sh"
similarity index 52%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\345\234\206\346\213\254\345\217\267.sh"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\345\234\206\346\213\254\345\217\267.sh"
index 984545ea..26002125 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\345\234\206\346\213\254\345\217\267.sh"
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\345\234\206\346\213\254\345\217\267.sh"
@@ -1,11 +1,12 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# using double parenthesis
var1=10
-if (( $var1 ** 2 > 90))
-then
- (( var2 = $var1 ** 2))
+if (($var1 ** 2 > 90))
+then
+ ((var2 = $var1 ** 2))
echo "The square of $var1 if $var2"
fi
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\346\226\271\346\213\254\345\217\267.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\346\226\271\346\213\254\345\217\267.sh"
similarity index 80%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\346\226\271\346\213\254\345\217\267.sh"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\346\226\271\346\213\254\345\217\267.sh"
index 4d76ecaa..8b9ce3f9 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\346\226\271\346\213\254\345\217\267.sh"
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\217\214\346\226\271\346\213\254\345\217\267.sh"
@@ -1,8 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# using pattern matching
if [[ $USER == r* ]]
-then
+then
echo "Hello $USER"
else
echo "Sorry, I do not know you"
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\351\224\231\350\257\257\347\232\204\344\275\277\347\224\250\345\244\247\344\272\216\345\260\217\344\272\216\345\217\267.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\244\247\344\272\216\345\260\217\344\272\216\345\217\267.sh"
similarity index 52%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\351\224\231\350\257\257\347\232\204\344\275\277\347\224\250\345\244\247\344\272\216\345\260\217\344\272\216\345\217\267.sh"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\244\247\344\272\216\345\260\217\344\272\216\345\217\267.sh"
index 7bc876b8..dcb58809 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\351\224\231\350\257\257\347\232\204\344\275\277\347\224\250\345\244\247\344\272\216\345\260\217\344\272\216\345\217\267.sh"
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\244\247\344\272\216\345\260\217\344\272\216\345\217\267.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# 大于小于号必须转义,否则shell会将它们当做重定向符号而把字符串值当做文件名处理
# 大于小于号顺序和sort命令所采用的有所不同
# mis-using string comparisons
@@ -6,7 +7,16 @@
val1=baseball
val2=hockey
-if [ $val1 > $val2 ]
+################### 错误使用大于小于号 ##################
+if [[ $val1 > $val2 ]]
+then
+ echo "$val1 is greater than $val2"
+else
+ echo "$val1 is less than $val2"
+fi
+
+################### 正确使用大于小于号 ###################
+if [[ $val1 \> $val2 ]]
then
echo "$val1 is greater than $val2"
else
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\265\214\345\245\227\345\276\252\347\216\257\345\271\266\344\277\256\346\224\271IFS.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\265\214\345\245\227\345\276\252\347\216\257\345\271\266\344\277\256\346\224\271IFS.sh"
similarity index 87%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\265\214\345\245\227\345\276\252\347\216\257\345\271\266\344\277\256\346\224\271IFS.sh"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\265\214\345\245\227\345\276\252\347\216\257\345\271\266\344\277\256\346\224\271IFS.sh"
index 5887c99b..b1c406cc 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\265\214\345\245\227\345\276\252\347\216\257\345\271\266\344\277\256\346\224\271IFS.sh"
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\345\265\214\345\245\227\345\276\252\347\216\257\345\271\266\344\277\256\346\224\271IFS.sh"
@@ -1,11 +1,11 @@
-#!/bin/bash
+#!/usr/bin/env bash
#changing the IFS value
IFS.OLD=$IFS
IFS=$'\n'
for entry in `cat /etc/passwd`
-do
+do
echo "Values in $entry -"
IFS=:
for value in $entry
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\347\256\241\351\201\223\346\210\226\351\207\215\345\256\232\345\220\221.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\347\256\241\351\201\223\346\210\226\351\207\215\345\256\232\345\220\221.sh"
similarity index 94%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\347\256\241\351\201\223\346\210\226\351\207\215\345\256\232\345\220\221.sh"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\347\256\241\351\201\223\346\210\226\351\207\215\345\256\232\345\220\221.sh"
index 7ec74a40..354c6c5a 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\347\256\241\351\201\223\346\210\226\351\207\215\345\256\232\345\220\221.sh"
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\347\256\241\351\201\223\346\210\226\351\207\215\345\256\232\345\220\221.sh"
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# redirecting the for output to a file
for file in /home/tiandi/*
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\351\200\232\351\205\215\347\254\246\345\244\204\347\220\206\347\233\256\345\275\225.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\351\200\232\351\205\215\347\254\246\345\244\204\347\220\206\347\233\256\345\275\225.sh"
similarity index 90%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\351\200\232\351\205\215\347\254\246\345\244\204\347\220\206\347\233\256\345\275\225.sh"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\351\200\232\351\205\215\347\254\246\345\244\204\347\220\206\347\233\256\345\275\225.sh"
index cc45dad4..81d03d74 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\351\200\232\351\205\215\347\254\246\345\244\204\347\220\206\347\233\256\345\275\225.sh"
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\344\275\277\347\224\250\351\200\232\351\205\215\347\254\246\345\244\204\347\220\206\347\233\256\345\275\225.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#iterate through all the files in a directory
for file in /home/tiandi/test/*
do
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\263\250\346\204\217test\345\244\247\345\260\217\345\206\231\351\241\272\345\272\217\345\222\214sort\344\270\215\345\220\214.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\346\263\250\346\204\217test\345\244\247\345\260\217\345\206\231\351\241\272\345\272\217\345\222\214sort\344\270\215\345\220\214.sh"
similarity index 95%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\263\250\346\204\217test\345\244\247\345\260\217\345\206\231\351\241\272\345\272\217\345\222\214sort\344\270\215\345\220\214.sh"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\346\263\250\346\204\217test\345\244\247\345\260\217\345\206\231\351\241\272\345\272\217\345\222\214sort\344\270\215\345\220\214.sh"
index 96123e40..282001b7 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\346\263\250\346\204\217test\345\244\247\345\260\217\345\206\231\351\241\272\345\272\217\345\222\214sort\344\270\215\345\220\214.sh"
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\346\263\250\346\204\217test\345\244\247\345\260\217\345\206\231\351\241\272\345\272\217\345\222\214sort\344\270\215\345\220\214.sh"
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
#test命令中,大小字母会被当成小于小写字符,而在sort中,小写字母会先出现,test使用标准的ASCII排序,sort使用本地化语言设置进行排序,对于英语,本地化设置制定了排序顺序中小写字母出现在大写字母之前
var1=Testing
diff --git "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\350\257\273\345\217\226\351\207\214\350\241\250\344\270\255\345\244\215\346\235\202\347\232\204\345\200\274.sh" "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\350\257\273\345\217\226\351\207\214\350\241\250\344\270\255\345\244\215\346\235\202\347\232\204\345\200\274.sh"
similarity index 83%
rename from "codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\350\257\273\345\217\226\351\207\214\350\241\250\344\270\255\345\244\215\346\235\202\347\232\204\345\200\274.sh"
rename to "codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\350\257\273\345\217\226\351\207\214\350\241\250\344\270\255\345\244\215\346\235\202\347\232\204\345\200\274.sh"
index 52034e74..bae02da2 100644
--- "a/codes/shell/\347\244\272\344\276\213\350\204\232\346\234\254/\351\200\273\350\276\221\346\216\247\345\210\266/\350\257\273\345\217\226\351\207\214\350\241\250\344\270\255\345\244\215\346\235\202\347\232\204\345\200\274.sh"
+++ "b/codes/shell/\351\200\273\350\276\221\346\216\247\345\210\266/\350\257\273\345\217\226\351\207\214\350\241\250\344\270\255\345\244\215\346\235\202\347\232\204\345\200\274.sh"
@@ -1,8 +1,8 @@
-#!/bin/bash
+#!/usr/bin/env bash
# another example of how not to use the for command
for test in I don't know if this'll work
-do
+do
echo "word:$test"
done
diff --git a/docs/.remarkrc b/docs/.remarkrc
new file mode 100644
index 00000000..5accdbba
--- /dev/null
+++ b/docs/.remarkrc
@@ -0,0 +1,9 @@
+{
+ "plugins": [
+ "preset-lint-recommended",
+ "preset-lint-consistent",
+
+ ["lint-list-item-indent", "space"],
+ ["lint-heading-style", false]
+ ]
+}
diff --git a/docs/.textlint.terms.json b/docs/.textlint.terms.json
new file mode 100644
index 00000000..7ea8ecd7
--- /dev/null
+++ b/docs/.textlint.terms.json
@@ -0,0 +1,8 @@
+[
+ "Stylus",
+ "VuePress",
+ [
+ "front[- ]matter",
+ "frontmatter"
+ ]
+]
diff --git a/docs/.textlintrc.js b/docs/.textlintrc.js
new file mode 100644
index 00000000..068b522b
--- /dev/null
+++ b/docs/.textlintrc.js
@@ -0,0 +1,23 @@
+module.exports = {
+ rules: {
+ '@textlint-rule/no-unmatched-pair': true,
+ apostrophe: true,
+ 'common-misspellings': true,
+ diacritics: true,
+ 'en-capitalization': {
+ allowHeading: false
+ },
+ 'stop-words': {
+ severity: 'warning'
+ },
+ terminology: {
+ terms: `${__dirname}/.textlint.terms.json`
+ },
+ 'write-good': {
+ severity: 'warning'
+ }
+ },
+ filters: {
+ comments: true
+ }
+}
diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js
new file mode 100644
index 00000000..24645b9f
--- /dev/null
+++ b/docs/.vuepress/config.js
@@ -0,0 +1,106 @@
+/**
+ * @see https://vuepress.vuejs.org/zh/
+ */
+module.exports = {
+ port: '4000',
+ dest: 'dist',
+ base: '/linux-tutorial/',
+ title: 'LINUX-TUTORIAL',
+ description: '数据库教程',
+ head: [['link', { rel: 'icon', href: `/favicon.ico` }]],
+ markdown: {
+ externalLinks: {
+ target: '_blank',
+ rel: 'noopener noreferrer',
+ },
+ },
+ themeConfig: {
+ logo: '/images/dunwu-logo-100.png',
+ repo: 'dunwu/linux-tutorial',
+ repoLabel: 'Github',
+ docsDir: 'docs',
+ docsBranch: 'master',
+ editLinks: true,
+ smoothScroll: true,
+ locales: {
+ '/': {
+ label: '简体中文',
+ selectText: 'Languages',
+ editLinkText: '帮助我们改善此页面!',
+ lastUpdated: '上次更新',
+ nav: [
+ {
+ text: 'Linux 命令',
+ link: '/linux/cli/',
+ },
+ {
+ text: 'Linux 运维',
+ link: '/linux/ops/',
+ },
+ {
+ text: 'Linux 软件运维',
+ link: '/linux/soft/',
+ },
+ {
+ text: 'Docker 教程',
+ link: '/docker/',
+ },
+ {
+ text: '🎯 博客',
+ link: 'https://github.com/dunwu/blog',
+ target: '_blank',
+ rel: '',
+ },
+ ],
+ sidebar: 'auto',
+ sidebarDepth: 2,
+ },
+ },
+ },
+ plugins: [
+ [
+ '@vuepress/active-header-links',
+ {
+ sidebarLinkSelector: '.sidebar-link',
+ headerAnchorSelector: '.header-anchor',
+ },
+ ],
+ ['@vuepress/back-to-top', true],
+ [
+ '@vuepress/pwa',
+ {
+ serviceWorker: true,
+ updatePopup: true,
+ },
+ ],
+ [
+ '@vuepress/last-updated',
+ {
+ transformer: (timestamp, lang) => {
+ // 不要忘了安装 moment
+ const moment = require('moment')
+ moment.locale(lang)
+ return moment(timestamp).fromNow()
+ },
+ },
+ ],
+ ['@vuepress/medium-zoom', true],
+ [
+ 'container',
+ {
+ type: 'vue',
+ before: '',
+ after: ' ',
+ },
+ ],
+ [
+ 'container',
+ {
+ type: 'upgrade',
+ before: (info) => ``,
+ after: ' ',
+ },
+ ],
+ ['flowchart'],
+ ],
+}
diff --git a/docs/.vuepress/enhanceApp.js b/docs/.vuepress/enhanceApp.js
new file mode 100644
index 00000000..7b3605fc
--- /dev/null
+++ b/docs/.vuepress/enhanceApp.js
@@ -0,0 +1,7 @@
+export default ({ Vue, isServer }) => {
+ if (!isServer) {
+ import('vue-toasted' /* webpackChunkName: "notification" */).then(module => {
+ Vue.use(module.default)
+ })
+ }
+}
diff --git a/docs/.vuepress/public/favicon.ico b/docs/.vuepress/public/favicon.ico
new file mode 100644
index 00000000..51e9bfa0
Binary files /dev/null and b/docs/.vuepress/public/favicon.ico differ
diff --git a/docs/.vuepress/public/images/dunwu-logo-100.png b/docs/.vuepress/public/images/dunwu-logo-100.png
new file mode 100644
index 00000000..12d81778
Binary files /dev/null and b/docs/.vuepress/public/images/dunwu-logo-100.png differ
diff --git a/docs/.vuepress/public/images/dunwu-logo-200.png b/docs/.vuepress/public/images/dunwu-logo-200.png
new file mode 100644
index 00000000..ea0a019c
Binary files /dev/null and b/docs/.vuepress/public/images/dunwu-logo-200.png differ
diff --git a/docs/.vuepress/public/images/dunwu-logo-50.png b/docs/.vuepress/public/images/dunwu-logo-50.png
new file mode 100644
index 00000000..90a19762
Binary files /dev/null and b/docs/.vuepress/public/images/dunwu-logo-50.png differ
diff --git a/docs/.vuepress/public/images/dunwu-logo.png b/docs/.vuepress/public/images/dunwu-logo.png
new file mode 100644
index 00000000..61570e2a
Binary files /dev/null and b/docs/.vuepress/public/images/dunwu-logo.png differ
diff --git a/docs/README.md b/docs/README.md
index e41a86b9..8cf2000b 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,96 +1,120 @@
-# Linux 教程
-
-> :keyboard: 项目同步维护在 [github](https://github.com/dunwu/linux-tutorial) | [gitee](https://gitee.com/turnon/linux-tutorial)
+---
+home: true
+heroImage: https://raw.githubusercontent.com/dunwu/images/master/common/dunwu-logo.png
+heroText: LINUX-TUTORIAL
+tagline: 📚 linux-tutorial 是一个 Linux 教程。
+actionLink: /
+footer: CC-BY-SA-4.0 Licensed | Copyright © 2018-Now Dunwu
+---
+
+
+
+
+> 📚 **linux-tutorial** 是一个 Linux 教程。
+>
+> 🔁 项目同步维护在 [github](https://github.com/dunwu/linux-tutorial) | [gitee](https://gitee.com/turnon/linux-tutorial)
>
-> :book: [电子书](https://dunwu.github.io/linux-tutorial/) | [电子书(国内)](http://turnon.gitee.io/linux-tutorial/)
+> 📖 [电子书](https://dunwu.github.io/linux-tutorial/) | [电子书(国内)](http://turnon.gitee.io/linux-tutorial/)
+
+## 📖 内容
+
+### Linux 命令
+
+> 学习 Linux 的第一步:当然是从 [Linux 命令](linux/cli/README.md) 入手了。
-| :wrench: | :shell: | :memo: | :books: |
-| :-------------------: | :-------------------: | :---------------: | :-------------------: |
-| [软件运维](#软件运维) | [运维脚本](#运维脚本) | [知识点](#知识点) | [学习资源](#学习资源) |
+- [查看 Linux 命令帮助信息](linux/cli/linux-cli-help.md) - 关键词:`help`, `whatis`, `info`, `which`, `whereis`, `man`
+- [Linux 文件目录管理](linux/cli/linux-cli-dir.md) - 关键词:`cd`, `ls`, `pwd`, `mkdir`, `rmdir`, `tree`, `touch`, `ln`, `rename`, `stat`, `file`, `chmod`, `chown`, `locate`, `find`, `cp`, `mv`, `rm`
+- [Linux 文件内容查看命令](linux/cli/linux-cli-file.md) - 关键词:`cat`, `head`, `tail`, `more`, `less`, `sed`, `vi`, `grep`
+- [Linux 文件压缩和解压](linux/cli/linux-cli-file-compress.md) - 关键词:`tar`, `gzip`, `zip`, `unzip`
+- [Linux 用户管理](linux/cli/linux-cli-user.md) - 关键词:`groupadd`, `groupdel`, `groupmod`, `useradd`, `userdel`, `usermod`, `passwd`, `su`, `sudo`
+- [Linux 系统管理](linux/cli/linux-cli-system.md) - 关键词:`reboot`, `exit`, `shutdown`, `date`, `mount`, `umount`, `ps`, `kill`, `systemctl`, `service`, `crontab`
+- [Linux 网络管理](linux/cli/linux-cli-net.md) - 关键词:关键词:`curl`, `wget`, `telnet`, `ip`, `hostname`, `ifconfig`, `route`, `ssh`, `ssh-keygen`, `firewalld`, `iptables`, `host`, `nslookup`, `nc`/`netcat`, `ping`, `traceroute`, `netstat`
+- [Linux 硬件管理](linux/cli/linux-cli-hardware.md) - 关键词:`df`, `du`, `top`, `free`, `iotop`
+- [Linux 软件管理](linux/cli/linux-cli-software.md) - 关键词:`rpm`, `yum`, `apt-get`
-## 软件运维
+### Linux 运维
-> 本章节内容介绍日常开发中常见的一些软件、工具的安装、配置。
+> Linux 系统的常见运维工作。
+
+- [网络运维](linux/ops/network-ops.md)
+- [Samba](linux/ops/samba.md)
+- [NTP](linux/ops/ntp.md)
+- [Firewalld](linux/ops/firewalld.md)
+- [Crontab](linux/ops/crontab.md)
+- [Systemd](linux/ops/systemd.md)
+- [Vim](linux/ops/vim.md)
+- [Iptables](linux/ops/iptables.md)
+- [oh-my-zsh](linux/ops/zsh.md)
+
+### 软件运维
+
+> 部署在 Linux 系统上的软件运维。
+>
+> 配套安装脚本:⌨ [软件运维配置脚本集合](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft)
- 开发环境
- [JDK 安装](linux/soft/jdk-install.md)
- [Maven 安装](linux/soft/maven-install.md)
- [Nodejs 安装](linux/soft/nodejs-install.md)
- 开发工具
- - [Nexus 运维](linux/soft/nexus-install.md)
- - [Gitlab 运维](linux/soft/kafka-install.md)
- - [Jenkins 运维](linux/soft/jenkins.md)
+ - [Nexus 运维](linux/soft/nexus-ops.md)
+ - [Gitlab 运维](linux/soft/gitlab-ops.md)
+ - [Jenkins 运维](linux/soft/jenkins-ops.md)
- [Svn 运维](linux/soft/svn-ops.md)
- [YApi 运维](linux/soft/yapi-ops.md)
- 中间件服务
- [Elastic 运维](linux/soft/elastic)
- [Kafka 运维](linux/soft/kafka-install.md)
- [RocketMQ 运维](linux/soft/rocketmq-install.md)
- - [Zookeeper 运维](linux/soft/zookeeper-install.md)
+ - [Zookeeper 运维](https://github.com/dunwu/javatech/blob/master/docs/technology/monitor/zookeeper-ops.md)
- [Nacos 运维](linux/soft/nacos-install.md)
- 服务器
- - [Nginx 教程](https://github.com/dunwu/nginx-tutorial)
+ - [Nginx 教程](https://github.com/dunwu/nginx-tutorial) 📚
- [Tomcat 运维](linux/soft/tomcat-install.md)
-- 数据库
- - [Mongodb 运维](linux/soft/mongodb-ops.md)
- - [Redis 运维](linux/soft/redis-ops.md)
-
-## 运维脚本
-
-- [系统运维脚本集合](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/sys)
-- [软件运维配置脚本集合](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft)
-- [工具脚本集合](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft)
-- [Vim 应用指南](linux/ops/vim.md)
-- [Zsh 应用指南](linux/ops/zsh.md)
-- [Shell 教程](linux/ops/shell.md)
-- [Python 教程](linux/ops/python.md)
-
-> 提供一键式运维、配置软件脚本
-
-## 知识点
-
-### Linux
-
-- [Linux 命令教程](linux/cli/README.md)
- - [查看 Linux 命令帮助信息](linux/cli/查看Linux命令帮助信息.md)
- - [Linux 文件目录管理](linux/cli/Linux文件目录管理.md)
- - [Linux 文件内容查看命令](linux/cli/Linux文件内容查看编辑.md)
- - [Linux 文件压缩和解压](linux/cli/Linux文件压缩和解压.md)
- - [Linux 用户管理](linux/cli/Linux用户管理.md)
- - [Linux 系统管理](linux/cli/Linux系统管理.md)
- - [Linux 网络管理](linux/cli/Linux网络管理.md)
- - [Linux 硬件管理](linux/cli/Linux硬件管理.md)
- - [Linux 软件管理](linux/cli/Linux硬件管理.md)
-- [Linux 运维](linux/ops/README.md)
- - [linux 典型运维应用](linux/ops/linux典型运维应用.md)
- - [samba 使用详解](linux/ops/samba使用详解.md)
+- [数据库](https://github.com/dunwu/db-tutorial) 📚
+ - [Mysql 运维](https://github.com/dunwu/db-tutorial/blob/master/docs/sql/mysql/mysql-ops.md)
+ - [Redis 运维](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-ops.md)
### Docker
-- [Docker 教程](docker)
- - [Docker 应用指南](docker/docker.md)
- - [Docker Cheat Sheet](docker/docker-cheat-sheet.md)
+- [Docker 快速入门](docker/docker-quickstart.md)
+- [Dockerfile 最佳实践](docker/docker-dockerfile.md)
+- [Docker Cheat Sheet](docker/docker-cheat-sheet.md)
+- [Kubernetes 应用指南](docker/kubernetes.md)
-### Git
+### 其他
-- [Git 教程](git/README.md)
- - [Git 快速指南](git/git-quickstart.md)
- - [Git 配置](git/git-configuration.md)
- - [git-flow 工作流](git/git-flow.md)
- - [Git 常见问题](git/git-faq.md)
+- [一篇文章让你彻底掌握 Python](https://dunwu.github.io/blog/pages/ef501b/)
+- [一篇文章让你彻底掌握 Shell](https://dunwu.github.io/blog/pages/ea6ae1/)
+- [如何优雅的玩转 Git](https://dunwu.github.io/blog/pages/2fc8b1/)
-## 学习资源
+## ⌨ 脚本
-- 命令行检索
- - [Linux 命令大全](http://man.linuxde.net/)
- - [linux-command](https://jaywcjlove.gitee.io/linux-command/)
-- 社区网站
+### Shell 脚本大全
+
+**Shell 脚本大全** 精心收集、整理了 Linux 环境下的常见 Shell 脚本操作片段。
+
+源码:[**Shell 脚本大全**](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell)
+
+### CentOS 运维脚本集合
+
+本人作为一名 Java 后端,苦于经常在 CentOS 环境上开荒虚拟机。为提高效率,写了一套 Shell 脚本,提供如下功能:安装常用 lib 库、命令工具、设置 DNS、NTP、配置国内 yum 源、一键安装常用软件等。
+
+源码:[**CentOS 常规操作运维脚本集合**](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux)
+
+## 📚 资料
+
+- **Linux 命令**
+ - [命令行的艺术](https://github.com/jlevy/the-art-of-command-line/blob/master/README-zh.md)
+ - [Linux 命令大全](https://man.linuxde.net/)
+ - [linux-command](https://github.com/jaywcjlove/linux-command)
+- **社区网站**
- [Linux 中国](https://linux.cn/) - 各种资讯、文章、技术
- [实验楼](https://www.shiyanlou.com/) - 免费提供了 Linux 在线环境,不用在自己机子上装系统也可以学习 Linux,超方便实用。
- [鸟哥的 linux 私房菜](http://linux.vbird.org/) - 非常适合 Linux 入门初学者看的教程。
- [Linux 公社](http://www.linuxidc.com/) - Linux 相关的新闻、教程、主题、壁纸都有。
- [Linux Today](http://www.linuxde.net) - Linux 新闻资讯发布,Linux 职业技术学习!。
-- 知识相关
+- **知识相关**
- [Linux 思维导图整理](http://www.jianshu.com/p/59f759207862)
- [Linux 初学者进阶学习资源整理](http://www.jianshu.com/p/fe2a790b41eb)
- [Linux 基础入门(新版)](https://www.shiyanlou.com/courses/1)
@@ -99,7 +123,7 @@
- [Linux 编程之内存映射](https://www.shiyanlou.com/questions/2992)
- [Linux 知识点小结](https://blog.huachao.me/2016/1/Linux%E7%9F%A5%E8%AF%86%E7%82%B9%E5%B0%8F%E7%BB%93/)
- [10 大白帽黑客专用的 Linux 操作系统](https://linux.cn/article-6971-1.html)
-- 软件工具
+- **软件工具**
- [超赞的 Linux 软件](https://www.gitbook.com/book/alim0x/awesome-linux-software-zh_cn/details) Github 仓库[Zh](https://github.com/alim0x/Awesome-Linux-Software-zh_CN) [En](https://github.com/VoLuong/Awesome-Linux-Software)
- [程序员喜欢的 9 款最佳的 Linux 文件比较工具](http://os.51cto.com/art/201607/513796.htm)
- [提高 Linux 开发效率的 5 个工具](http://www.codeceo.com/article/5-linux-productivity-tools.html)
@@ -114,7 +138,7 @@
- [Webflow (Adobe Muse)](https://webflow.com/) 一款可以帮助用户不用编码就可以快速创建网站的谷歌浏览器插件。
- [Tupi (Adobe Animate)](http://www.maefloresta.com/portal/) 一款可以创建 HTML5 动画的工具。
- [Black Magic Fusion (Adobe After Effects)](https://www.blackmagicdesign.com) 一款先进的合成软件,广泛应用于视觉特效、广电影视设计以及 3D 动画设计等领域。
-- 中国开源镜像站点
+- **中国开源镜像**
- [阿里云开源镜像站](http://mirrors.aliyun.com/)
- [网易开源镜像站](http://mirrors.163.com/)
- [搜狐开源镜像站](http://mirrors.sohu.com/)
@@ -127,3 +151,7 @@
- [东北大学](http://mirror.neu.edu.cn/)
- [浙江大学](http://mirrors.zju.edu.cn/)
- [东软信息学院](http://mirrors.neusoft.edu.cn/)
+
+## 🚪 传送门
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾ 🎯 [钝悟的博客](https://dunwu.github.io/blog/) ◾
diff --git a/docs/coverpage.md b/docs/coverpage.md
deleted file mode 100644
index 6a08035d..00000000
--- a/docs/coverpage.md
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-# Linux 教程
-
-> Linux 教程
-
-[开始阅读](README.md)
diff --git a/docs/docker/README.md b/docs/docker/README.md
index 1eb4ac7a..7434bbcb 100644
--- a/docs/docker/README.md
+++ b/docs/docker/README.md
@@ -1 +1,36 @@
# Docker 教程
+
+## 📖 内容
+
+- [Docker 快速入门](docker-quickstart.md)
+- [Dockerfile 最佳实践](docker-dockerfile.md)
+- [Docker Cheat Sheet](docker-cheat-sheet.md)
+- [Kubernetes 应用指南](kubernetes.md)
+
+## 📚 资料
+
+- **官方**
+ - [Docker 官网](http://www.docker.com)
+ - [Docker 官方文档](https://docs.docker.com/)
+ - [Docker Github](https://github.com/moby/moby)
+ - [Docker Compose Github](https://github.com/docker/compose)
+ - [Docker Hub](https://hub.docker.com/)
+ - [Docker 开源](https://www.docker.com/community/open-source)
+- **资源整理**
+ - [Awesome Docker](https://github.com/veggiemonk/awesome-docker)
+- **教程**
+ - [Docker — 从入门到实践](https://github.com/yeasy/docker_practice) - 非常详尽的 Docker 中文教程
+ - [Docker 中文网站](https://www.docker-cn.com/)
+ - [Docker 安装手册](https://docs.docker-cn.com/engine/installation/)
+- **镜像**
+ - [时速云镜像仓库](https://hub.tenxcloud.com/)
+ - [网易云镜像服务](https://c.163.com/hub#/m/library/)
+ - [DaoCloud 镜像市场](https://hub.daocloud.io/)
+ - [阿里云镜像库](https://cr.console.aliyun.com/)
+- **文章**
+ - [Docker 入门教程](http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html)
+ - [Docker Cheat Sheet](https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn)
+
+## 🚪 传送门
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾ 🎯 [钝悟的博客](https://dunwu.github.io/blog/) ◾
diff --git a/docs/docker/advanced/docker-design.md b/docs/docker/advanced/docker-design.md
deleted file mode 100644
index 47148d59..00000000
--- a/docs/docker/advanced/docker-design.md
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
-- [Docker 的设计](#docker-%E7%9A%84%E8%AE%BE%E8%AE%A1)
- - [Docker 架构](#docker-%E6%9E%B6%E6%9E%84)
- - [Docker 守护进程(docker daemon)](#docker-%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B%EF%BC%88docker-daemon%EF%BC%89)
- - [Docker 客户端](#docker-%E5%AE%A2%E6%88%B7%E7%AB%AF)
- - [Docker 注册中心](#docker-%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83)
- - [Docker 对象](#docker-%E5%AF%B9%E8%B1%A1)
- - [镜像](#%E9%95%9C%E5%83%8F)
- - [容器](#%E5%AE%B9%E5%99%A8)
- - [服务](#%E6%9C%8D%E5%8A%A1)
- - [底层技术](#%E5%BA%95%E5%B1%82%E6%8A%80%E6%9C%AF)
- - [命名空间](#%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4)
- - [控制组](#%E6%8E%A7%E5%88%B6%E7%BB%84)
- - [联合文件系统](#%E8%81%94%E5%90%88%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F)
- - [容器格式](#%E5%AE%B9%E5%99%A8%E6%A0%BC%E5%BC%8F)
- - [资料](#%E8%B5%84%E6%96%99)
-
-
-
-# Docker 的设计
-
-## Docker 架构
-
-Docker 使用 C/S 体系结构。Docker 守护进程,负责构建、运行和分发 Docker 容器;Docker 客户端与 Docker 守护进程通信。Docker 客户端和守护进程可以在同一个系统上运行,也可以将 Docker 客户端连接到远程 Docker 守护进程。Docker 客户端和守护进程使用 REST API,并通过 UNIX 套接字或网络接口进行通信。
-
-
-
-### Docker 守护进程(docker daemon)
-
-Docker 守护进程(`dockerd`)监听 Docker API 请求并管理 Docker 对象(如镜像,容器,网络和卷)。守护进程还可以与其他守护进程通信来管理 Docker 服务。
-
-### Docker 客户端
-
-Docker 客户端(`docker`)是许多 Docker 用户与 Docker 进行交互的主要方式。当你使用诸如 `docker run` 之类的命令时,客户端将这些命令发送到 `dockerd`,`dockerd` 执行这些命令。 `docker` 命令使用 Docker API。 Docker 客户端可以与多个守护进程进行通信。
-
-### Docker 注册中心
-
-Docker 注册中心存储 Docker 镜像。Docker Hub 和 Docker Cloud 是任何人都可以使用的公共注册中心,并且 Docker 默认配置为在 Docker Hub 上查找镜像。你甚至可以运行你自己的私人注册中心。如果您使用 Docker Datacenter(DDC),它包括 Docker Trusted Registry(DTR)。
-
-当您使用 `docker pull` 或 `docker run` 命令时,所需的镜像将从配置的注册中心中提取。当您使用 `docker push` 命令时,您的镜像将被推送到您配置的注册中心。
-
-[Docker 商店](http://store.docker.com/) 允许您购买和销售 Docker 镜像或免费发布。例如,您可以购买包含来自软件供应商的应用程序或服务的 Docker 镜像,并使用该镜像将应用程序部署到您的测试,临时和生产环境中。您可以通过拉取新版本的镜像并重新部署容器来升级应用程序。
-
-### Docker 对象
-
-#### 镜像
-
-镜像是一个只读模板,带有创建 Docker 容器的说明。通常,镜像基于另一个镜像,并具有一些额外的自定义功能。例如,您可以构建基于 ubuntu 镜像的镜像,但会安装 Apache Web 服务器和应用程序,以及使应用程序运行所需的配置细节。
-
-您可能会创建自己的镜像,或者您可能只能使用其他人创建并在注册中心中发布的镜像。为了构建您自己的镜像,您可以使用简单的语法创建 `Dockerfile`,以定义创建镜像并运行所需的步骤。 `Dockerfile` 中的每条指令都会在镜像中创建一个图层。当您更改 `Dockerfile` 并重建镜像时,只重建那些已更改的图层。与其他虚拟化技术相比,这是使镜像轻量,小巧,快速的一部分。
-
-#### 容器
-
-容器是镜像的可运行实例。您可以使用 Docker API 或 CLI 创建、启动、停止、移动或删除容器。您可以将容器连接到一个或多个网络,将存储器连接到它,甚至可以根据其当前状态创建新镜像。
-
-默认情况下,容器与其他容器及其主机相对隔离。您可以控制容器的网络、存储或其他底层子系统与其他容器或主机的隔离程度。
-
-容器由其镜像以及您在创建或启动时提供给它的任何配置选项来定义。当一个容器被移除时,其未被存储在永久存储器中的状态将消失。
-
-#### 服务
-
-通过服务,您可以跨多个 Docker 守护进程扩展容器,这些守护进程可以作为一个群组与多个管理人员、工作人员一起工作。集群中的每个成员都是 Docker 守护进程,守护进程都使用 Docker API 进行通信。服务允许您定义所需的状态,例如在任何给定时间必须可用的服务的副本数量。默认情况下,该服务在所有工作节点之间进行负载平衡。对于消费者来说,Docker 服务似乎是一个单一的应用程序。Docker 引擎在 Docker 1.12 及更高版本中支持集群模式。
-
-## 底层技术
-
-Docker 使用 Go 编写,利用 Linux 内核的几个特性来提供其功能。
-
-### 命名空间
-
-Docker 使用名为 `namespaces` 的技术来提供独立工作空间(即容器)。当你运行一个容器时,Docker 会为该容器创建一组命名空间。
-
-这些命名空间提供了一个隔离层。容器的每个方面都在单独的命名空间中运行,并且其访问权限限于该命名空间。
-
-Docker 引擎在 Linux 上使用如下的命名空间:
-
-* `pid` 命名空间:进程隔离(PID:进程ID)。
-* `net` 命名空间:管理网络接口(NET:网络)。
-* `ipc` 命名空间:管理对IPC资源的访问(IPC:InterProcess Communication)。
-* `mnt` 命名空间:管理文件系统挂载点(MNT:挂载)。
-* `uts` 命名空间:隔离内核和版本标识符。 (UTS:Unix分时系统)。
-
-### 控制组
-
-Linux 上的 Docker Engine 也依赖于另一种称为控制组(`cgroups`)的技术。 cgroup 将应用程序限制为一组特定的资源。控制组允许 Docker 引擎将可用硬件资源共享给容器,并可选地强制实施限制和约束。例如,您可以限制可用于特定容器的内存。
-
-### 联合文件系统
-
-联合文件系统(UnionFS)是通过创建图层进行操作的文件系统,这使它们非常轻巧和快速。 Docker 引擎使用 UnionFS 为容器提供构建块。Docker 引擎可以使用多种 UnionFS 变体,包括 AUFS,btrfs,vfs 和 DeviceMapper。
-
-### 容器格式
-
-Docker 引擎将命名空间,控制组和 UnionFS 组合成一个名为容器格式的包装器。默认的容器格式是`libcontainer`。将来,Docker 可以通过与诸如 BSD Jails 或 Solaris Zones 等技术集成来支持其他容器格式。
-
-## 资料
-
-* https://docs.docker.com/engine/docker-overview/
diff --git a/docs/docker/basics/docker-container.md b/docs/docker/basics/docker-container.md
deleted file mode 100644
index c993a7be..00000000
--- a/docs/docker/basics/docker-container.md
+++ /dev/null
@@ -1,261 +0,0 @@
-# Docker 容器
-
-容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。
-
-
-
-- [启动容器](#启动容器)
- - [新建并启动](#新建并启动)
- - [启动已终止容器](#启动已终止容器)
-- [后台运行](#后台运行)
-- [终止容器](#终止容器)
-- [进入容器](#进入容器)
- - [`attach` 命令](#attach-命令)
- - [`exec` 命令](#exec-命令)
-- [导出和导入容器](#导出和导入容器)
- - [导出容器](#导出容器)
- - [导入容器快照](#导入容器快照)
-- [删除容器](#删除容器)
-- [清理所有处于终止状态的容器](#清理所有处于终止状态的容器)
-
-
-
-## 启动容器
-
-启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(`stopped`)的容器重新启动。
-
-因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。
-
-### 新建并启动
-
-所需要的命令主要为 `docker run`。
-
-例如,下面的命令输出一个 “Hello World”,之后终止容器。
-
-```bash
-$ docker run ubuntu:14.04 /bin/echo 'Hello world'
-Hello world
-```
-
-这跟在本地直接执行 `/bin/echo 'hello world'` 几乎感觉不出任何区别。
-
-下面的命令则启动一个 bash 终端,允许用户进行交互。
-
-```bash
-$ docker run -t -i ubuntu:14.04 /bin/bash
-root@af8bae53bdd3:/#
-```
-
-其中,`-t` 选项让 Docker 分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, `-i` 则让容器的标准输入保持打开。
-
-在交互模式下,用户可以通过所创建的终端来输入命令,例如
-
-```bash
-root@af8bae53bdd3:/# pwd
-/
-root@af8bae53bdd3:/# ls
-bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
-```
-
-当利用 `docker run` 来创建容器时,Docker 在后台运行的标准操作包括:
-
-- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
-- 利用镜像创建并启动一个容器
-- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
-- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
-- 从地址池配置一个 ip 地址给容器
-- 执行用户指定的应用程序
-- 执行完毕后容器被终止
-
-### 启动已终止容器
-
-可以利用 `docker container start` 命令,直接将一个已经终止的容器启动运行。
-
-容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。除此之外,并没有其它的资源。可以在伪终端中利用 `ps` 或 `top` 来查看进程信息。
-
-```bash
-root@ba267838cc1b:/# ps
- PID TTY TIME CMD
- 1 ? 00:00:00 bash
- 11 ? 00:00:00 ps
-```
-
-可见,容器中仅运行了指定的 bash 应用。这种特点使得 Docker 对资源的利用率极高,是货真价实的轻量级虚拟化。
-
-## 后台运行
-
-更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 `-d` 参数来实现。
-
-下面举两个例子来说明一下。
-
-如果不使用 `-d` 参数运行容器。
-
-```bash
-$ docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
-hello world
-hello world
-hello world
-hello world
-```
-
-容器会把输出的结果 (STDOUT) 打印到宿主机上面
-
-如果使用了 `-d` 参数运行容器。
-
-```bash
-$ docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
-77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a
-```
-
-此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面(输出结果可以用 `docker logs` 查看)。
-
-**注:** 容器是否会长久运行,是和 `docker run` 指定的命令有关,和 `-d` 参数无关。
-
-使用 `-d` 参数启动后会返回一个唯一的 id,也可以通过 `docker container ls` 命令来查看容器信息。
-
-```
-$ docker container ls
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-77b2dc01fe0f ubuntu:18.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright
-```
-
-要获取容器的输出信息,可以通过 `docker container logs` 命令。
-
-```bash
-$ docker container logs [container ID or NAMES]
-hello world
-hello world
-hello world
-. . .
-```
-
-## 终止容器
-
-可以使用 `docker container stop` 来终止一个运行中的容器。
-
-此外,当 Docker 容器中指定的应用终结时,容器也自动终止。
-
-例如对于上一章节中只启动了一个终端的容器,用户通过 `exit` 命令或 `Ctrl+d` 来退出终端时,所创建的容器立刻终止。
-
-终止状态的容器可以用 `docker container ls -a` 命令看到。例如
-
-```bash
-docker container ls -a
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-ba267838cc1b ubuntu:14.04 "/bin/bash" 30 minutes ago Exited (0) About a minute ago trusting_newton
-98e5efa7d997 training/webapp:latest "python app.py" About an hour ago Exited (0) 34 minutes ago backstabbing_pike
-```
-
-处于终止状态的容器,可以通过 `docker container start` 命令来重新启动。
-
-此外,`docker container restart` 命令会将一个运行态的容器终止,然后再重新启动它。
-
-## 进入容器
-
-在使用 `-d` 参数时,容器启动后会进入后台。
-
-某些时候需要进入容器进行操作,包括使用 `docker attach` 命令或 `docker exec` 命令,推荐大家使用 `docker exec` 命令,原因会在下面说明。
-
-### `attach` 命令
-
-`docker attach` 是 Docker 自带的命令。下面示例如何使用该命令。
-
-```bash
-$ docker run -dit ubuntu
-243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550
-
-$ docker container ls
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-243c32535da7 ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds nostalgic_hypatia
-
-$ docker attach 243c
-root@243c32535da7:/#
-```
-
-_注意:_ 如果从这个 stdin 中 exit,会导致容器的停止。
-
-### `exec` 命令
-
-#### -i -t 参数
-
-`docker exec` 后边可以跟多个参数,这里主要说明 `-i` `-t` 参数。
-
-只用 `-i` 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。
-
-当 `-i` `-t` 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。
-
-```bash
-$ docker run -dit ubuntu
-69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6
-
-$ docker container ls
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-69d137adef7a ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds zealous_swirles
-
-$ docker exec -i 69d1 bash
-ls
-bin
-boot
-dev
-...
-
-$ docker exec -it 69d1 bash
-root@69d137adef7a:/#
-```
-
-如果从这个 stdin 中 exit,不会导致容器的停止。这就是为什么推荐大家使用 `docker exec` 的原因。
-
-更多参数说明请使用 `docker exec --help` 查看。
-
-## 导出和导入容器
-
-### 导出容器
-
-如果要导出本地某个容器,可以使用 `docker export` 命令。
-
-```bash
-$ docker container ls -a
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-7691a814370e ubuntu:14.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test
-$ docker export 7691a814370e > ubuntu.tar
-```
-
-这样将导出容器快照到本地文件。
-
-### 导入容器快照
-
-可以使用 `docker import` 从容器快照文件中再导入为镜像,例如
-
-```bash
-$ cat ubuntu.tar | docker import - test/ubuntu:v1.0
-$ docker image ls
-REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
-test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB
-```
-
-此外,也可以通过指定 URL 或者某个目录来导入,例如
-
-```bash
-$ docker import http://example.com/exampleimage.tgz example/imagerepo
-```
-
-_注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。_
-
-## 删除容器
-
-可以使用 `docker container rm` 来删除一个处于终止状态的容器。例如
-
-```bash
-$ docker container rm trusting_newton
-trusting_newton
-```
-
-如果要删除一个运行中的容器,可以添加 `-f` 参数。Docker 会发送 `SIGKILL` 信号给容器。
-
-## 清理所有处于终止状态的容器
-
-用 `docker container ls -a` 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。
-
-```bash
-$ docker container prune
-```
diff --git a/docs/docker/basics/docker-helloworld.md b/docs/docker/basics/docker-helloworld.md
deleted file mode 100644
index 47134f77..00000000
--- a/docs/docker/basics/docker-helloworld.md
+++ /dev/null
@@ -1,71 +0,0 @@
-# Docker 之 Hello World
-
-## 前提
-
-确保你的环境上已经成功安装 Docker。
-
-## Hello World 实例
-
-1. 使用 `docker version` 命令确保你的环境已成功安装 Docker。
-
-```
-# docker version
-Client:
- Version: 1.13.1
- API version: 1.26
- Package version:
- Go version: go1.8.3
- Git commit: 774336d/1.13.1
- Built: Wed Mar 7 17:06:16 2018
- OS/Arch: linux/amd64
-
-Server:
- Version: 1.13.1
- API version: 1.26 (minimum version 1.12)
- Package version:
- Go version: go1.8.3
- Git commit: 774336d/1.13.1
- Built: Wed Mar 7 17:06:16 2018
- OS/Arch: linux/amd64
- Experimental: false
-```
-
-2. 使用 `docker run` 命令运行 Hello World 镜像。
-
-```
-docker run hello-world
-
-Unable to find image 'hello-world:latest' locally
-latest: Pulling from library/hello-world
-ca4f61b1923c: Pull complete
-Digest: sha256:ca0eeb6fb05351dfc8759c20733c91def84cb8007aa89a5bf606bc8b315b9fc7
-Status: Downloaded newer image for hello-world:latest
-
-Hello from Docker!
-This message shows that your installation appears to be working correctly.
-...
-```
-
-3. 使用 `docker image ls`命令查看镜像
-
-```
-docker image ls
-REPOSITORY TAG IMAGE ID CREATED SIZE
-docker.io/maven latest 76c9ab5df55b 7 days ago 737 MB
-docker.io/python 2.7-slim 5541369755c4 13 days ago 139 MB
-docker.io/hello-world latest f2a91732366c 4 months ago 1.85 kB
-docker.io/java 8-jre e44d62cf8862 14 months ago 311 MB
-docker.io/training/webapp latest 6fae60ef3446 2 years ago 349 MB
-```
-
-4. 使用 `docker container ls --all` 命令查看容器
-
-如果查看正在运行的容器,不需要添加 `--all` 参数。
-
-```
-docker container ls --all
-CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-a661d957c6fa hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago mystifying_swartz
-3098f24a1064 docker.io/hello-world "/hello" 6 minutes ago Exited (0) 6 minutes ago sad_yonath
-4c98c4f18a39 hello-world "/hello" 8 minutes ago Exited (0) 8 minutes ago admiring_banach
-```
diff --git a/docs/docker/basics/docker-image.md b/docs/docker/basics/docker-image.md
deleted file mode 100644
index ac6ca425..00000000
--- a/docs/docker/basics/docker-image.md
+++ /dev/null
@@ -1,491 +0,0 @@
-# Docker 镜像
-
-
-
-- [获取镜像](#获取镜像)
- - [运行](#运行)
-- [列出镜像](#列出镜像)
- - [镜像体积](#镜像体积)
- - [虚悬镜像](#虚悬镜像)
- - [中间层镜像](#中间层镜像)
- - [列出部分镜像](#列出部分镜像)
- - [以特定格式显示](#以特定格式显示)
-- [删除本地镜像](#删除本地镜像)
- - [用 ID、镜像名、摘要删除镜像](#用-id镜像名摘要删除镜像)
- - [Untagged 和 Deleted](#untagged-和-deleted)
- - [用 docker image ls 命令来配合](#用-docker-image-ls-命令来配合)
- - [CentOS/RHEL 的用户需要注意的事项](#centosrhel-的用户需要注意的事项)
-- [使用 Dockerfile 定制镜像](#使用-dockerfile-定制镜像)
- - [构建镜像](#构建镜像)
- - [镜像构建上下文(Context)](#镜像构建上下文context)
- - [其它 `docker build` 的用法](#其它-docker-build-的用法)
-
-
-
-## 获取镜像
-
-之前提到过,[Docker Hub](https://hub.docker.com/explore/) 上有大量的高质量的镜像可以用,这里我们就说一下怎么获取这些镜像。
-
-从 Docker 镜像仓库获取镜像的命令是 `docker pull`。其命令格式为:
-
-```bash
-docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
-```
-
-具体的选项可以通过 `docker pull --help` 命令看到,这里我们说一下镜像名称的格式。
-
-- Docker 镜像仓库地址:地址的格式一般是 `<域名/IP>[:端口号]`。默认地址是 Docker Hub。
-- 仓库名:如之前所说,这里的仓库名是两段式名称,即 `<用户名>/<软件名>`。对于 Docker Hub,如果不给出用户名,则默认为 `library`,也就是官方镜像。
-
-比如:
-
-```bash
-$ docker pull ubuntu:18.04
-18.04: Pulling from library/ubuntu
-bf5d46315322: Pull complete
-9f13e0ac480c: Pull complete
-e8988b5b3097: Pull complete
-40af181810e7: Pull complete
-e6f7c7e5c03e: Pull complete
-Digest: sha256:147913621d9cdea08853f6ba9116c2e27a3ceffecf3b492983ae97c3d643fbbe
-Status: Downloaded newer image for ubuntu:18.04
-```
-
-上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 `ubuntu:18.04`,因此将会获取官方镜像 `library/ubuntu` 仓库中标签为 `18.04` 的镜像。
-
-从下载过程中可以看到我们之前提及的分层存储的概念,镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 `sha256` 的摘要,以确保下载一致性。
-
-在使用上面命令的时候,你可能会发现,你所看到的层 ID 以及 `sha256` 的摘要和这里的不一样。这是因为官方镜像是一直在维护的,有任何新的 bug,或者版本更新,都会进行修复再以原来的标签发布,这样可以确保任何使用这个标签的用户可以获得更安全、更稳定的镜像。
-
-*如果从 Docker Hub 下载镜像非常缓慢,可以参照 镜像加速器 一节配置加速器。*
-
-### 运行
-
-有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 `ubuntu:18.04` 为例,如果我们打算启动里面的 `bash` 并且进行交互式操作的话,可以执行下面的命令。
-
-```bash
-$ docker run -it --rm \
- ubuntu:18.04 \
- bash
-
-root@e7009c6ce357:/# cat /etc/os-release
-NAME="Ubuntu"
-VERSION="18.04.1 LTS (Bionic Beaver)"
-ID=ubuntu
-ID_LIKE=debian
-PRETTY_NAME="Ubuntu 18.04.1 LTS"
-VERSION_ID="18.04"
-HOME_URL="https://www.ubuntu.com/"
-SUPPORT_URL="https://help.ubuntu.com/"
-BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
-PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
-VERSION_CODENAME=bionic
-UBUNTU_CODENAME=bionic
-```
-
-`docker run` 就是运行容器的命令,具体格式我们会在 [容器](https://yeasy.gitbooks.io/docker_practice/content/container) 一节进行详细讲解,我们这里简要的说明一下上面用到的参数。
-
-- `-it`:这是两个参数,一个是 `-i`:交互式操作,一个是 `-t` 终端。我们这里打算进入 `bash` 执行一些命令并查看返回结果,因此我们需要交互式终端。
-- `--rm`:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 `docker rm`。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 `--rm` 可以避免浪费空间。
-- `ubuntu:18.04`:这是指用 `ubuntu:18.04` 镜像为基础来启动容器。
-- `bash`:放在镜像名后的是**命令**,这里我们希望有个交互式 Shell,因此用的是 `bash`。
-
-进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 `cat /etc/os-release`,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 `Ubuntu 18.04.1 LTS` 系统。
-
-最后我们通过 `exit` 退出了这个容器。
-
-## 列出镜像
-
-要想列出已经下载下来的镜像,可以使用 `docker image ls` 命令。
-
-```bash
-$ docker image ls
-REPOSITORY TAG IMAGE ID CREATED SIZE
-redis latest 5f515359c7f8 5 days ago 183 MB
-nginx latest 05a60462f8ba 5 days ago 181 MB
-mongo 3.2 fe9198c04d62 5 days ago 342 MB
- 00285df0df87 5 days ago 342 MB
-ubuntu 18.04 f753707788c5 4 weeks ago 127 MB
-ubuntu latest f753707788c5 4 weeks ago 127 MB
-ubuntu 14.04 1e0c3dd64ccd 4 weeks ago 188 MB
-```
-
-列表包含了 `仓库名`、`标签`、`镜像 ID`、`创建时间` 以及 `所占用的空间`。
-
-其中仓库名、标签在之前的基础概念章节已经介绍过了。**镜像 ID** 则是镜像的唯一标识,一个镜像可以对应多个**标签**。因此,在上面的例子中,我们可以看到 `ubuntu:18.04` 和 `ubuntu:latest` 拥有相同的 ID,因为它们对应的是同一个镜像。
-
-### 镜像体积
-
-如果仔细观察,会注意到,这里标识的所占用空间和在 Docker Hub 上看到的镜像大小不同。比如,`ubuntu:18.04` 镜像大小,在这里是 `127 MB`,但是在 [Docker Hub](https://hub.docker.com/r/library/ubuntu/tags/) 显示的却是 `50 MB`。这是因为 Docker Hub 中显示的体积是压缩后的体积。在镜像下载和上传过程中镜像是保持着压缩状态的,因此 Docker Hub 所显示的大小是网络传输中更关心的流量大小。而 `docker image ls` 显示的是镜像下载到本地后,展开的大小,准确说,是展开后的各层所占空间的总和,因为镜像到本地后,查看空间的时候,更关心的是本地磁盘空间占用的大小。
-
-另外一个需要注意的问题是,`docker image ls` 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。
-
-你可以通过以下命令来便捷的查看镜像、容器、数据卷所占用的空间。
-
-```bash
-$ docker system df
-
-TYPE TOTAL ACTIVE SIZE RECLAIMABLE
-Images 24 0 1.992GB 1.992GB (100%)
-Containers 1 0 62.82MB 62.82MB (100%)
-Local Volumes 9 0 652.2MB 652.2MB (100%)
-Build Cache 0B 0B
-```
-
-### 虚悬镜像
-
-上面的镜像列表中,还可以看到一个特殊的镜像,这个镜像既没有仓库名,也没有标签,均为 ``。:
-
-```bash
- 00285df0df87 5 days ago 342 MB
-```
-
-这个镜像原本是有镜像名和标签的,原来为 `mongo:3.2`,随着官方镜像维护,发布了新版本后,重新 `docker pull mongo:3.2` 时,`mongo:3.2` 这个镜像名被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消,从而成为了 ``。除了 `docker pull` 可能导致这种情况,`docker build` 也同样可以导致这种现象。由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 `` 的镜像。这类无标签镜像也被称为 **虚悬镜像(dangling image)** ,可以用下面的命令专门显示这类镜像:
-
-```bash
-$ docker image ls -f dangling=true
-REPOSITORY TAG IMAGE ID CREATED SIZE
- 00285df0df87 5 days ago 342 MB
-```
-
-一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的命令删除。
-
-```bash
-$ docker image prune
-```
-
-### 中间层镜像
-
-为了加速镜像构建、重复利用资源,Docker 会利用 **中间层镜像**。所以在使用一段时间后,可能会看到一些依赖的中间层镜像。默认的 `docker image ls` 列表中只会显示顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加 `-a` 参数。
-
-```bash
-$ docker image ls -a
-```
-
-这样会看到很多无标签的镜像,与之前的虚悬镜像不同,这些无标签的镜像很多都是中间层镜像,是其它镜像所依赖的镜像。这些无标签镜像不应该删除,否则会导致上层镜像因为依赖丢失而出错。实际上,这些镜像也没必要删除,因为之前说过,相同的层只会存一遍,而这些镜像是别的镜像的依赖,因此并不会因为它们被列出来而多存了一份,无论如何你也会需要它们。只要删除那些依赖它们的镜像后,这些依赖的中间层镜像也会被连带删除。
-
-### 列出部分镜像
-
-不加任何参数的情况下,`docker image ls` 会列出所有顶级镜像,但是有时候我们只希望列出部分镜像。`docker image ls` 有好几个参数可以帮助做到这个事情。
-
-根据仓库名列出镜像
-
-```bash
-$ docker image ls ubuntu
-REPOSITORY TAG IMAGE ID CREATED SIZE
-ubuntu 18.04 f753707788c5 4 weeks ago 127 MB
-ubuntu latest f753707788c5 4 weeks ago 127 MB
-ubuntu 14.04 1e0c3dd64ccd 4 weeks ago 188 MB
-```
-
-列出特定的某个镜像,也就是说指定仓库名和标签
-
-```bash
-$ docker image ls ubuntu:18.04
-REPOSITORY TAG IMAGE ID CREATED SIZE
-ubuntu 18.04 f753707788c5 4 weeks ago 127 MB
-```
-
-除此以外,`docker image ls` 还支持强大的过滤器参数 `--filter`,或者简写 `-f`。之前我们已经看到了使用过滤器来列出虚悬镜像的用法,它还有更多的用法。比如,我们希望看到在 `mongo:3.2` 之后建立的镜像,可以用下面的命令:
-
-```bash
-$ docker image ls -f since=mongo:3.2
-REPOSITORY TAG IMAGE ID CREATED SIZE
-redis latest 5f515359c7f8 5 days ago 183 MB
-nginx latest 05a60462f8ba 5 days ago 181 MB
-```
-
-想查看某个位置之前的镜像也可以,只需要把 `since` 换成 `before` 即可。
-
-此外,如果镜像构建时,定义了 `LABEL`,还可以通过 `LABEL` 来过滤。
-
-```bash
-$ docker image ls -f label=com.example.version=0.1
-...
-```
-
-### 以特定格式显示
-
-默认情况下,`docker image ls` 会输出一个完整的表格,但是我们并非所有时候都会需要这些内容。比如,刚才删除虚悬镜像的时候,我们需要利用 `docker image ls` 把所有的虚悬镜像的 ID 列出来,然后才可以交给 `docker image rm` 命令作为参数来删除指定的这些镜像,这个时候就用到了 `-q` 参数。
-
-```bash
-$ docker image ls -q
-5f515359c7f8
-05a60462f8ba
-fe9198c04d62
-00285df0df87
-f753707788c5
-f753707788c5
-1e0c3dd64ccd
-```
-
-`--filter` 配合 `-q` 产生出指定范围的 ID 列表,然后送给另一个 `docker` 命令作为参数,从而针对这组实体成批的进行某种操作的做法在 Docker 命令行使用过程中非常常见,不仅仅是镜像,将来我们会在各个命令中看到这类搭配以完成很强大的功能。因此每次在文档看到过滤器后,可以多注意一下它们的用法。
-
-另外一些时候,我们可能只是对表格的结构不满意,希望自己组织列;或者不希望有标题,这样方便其它程序解析结果等,这就用到了 [Go 的模板语法](https://gohugo.io/templates/go-templates/)。
-
-比如,下面的命令会直接列出镜像结果,并且只包含镜像ID和仓库名:
-
-```bash
-$ docker image ls --format "{{.ID}}: {{.Repository}}"
-5f515359c7f8: redis
-05a60462f8ba: nginx
-fe9198c04d62: mongo
-00285df0df87:
-f753707788c5: ubuntu
-f753707788c5: ubuntu
-1e0c3dd64ccd: ubuntu
-```
-
-或者打算以表格等距显示,并且有标题行,和默认一样,不过自己定义列:
-
-```bash
-$ docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
-IMAGE ID REPOSITORY TAG
-5f515359c7f8 redis latest
-05a60462f8ba nginx latest
-fe9198c04d62 mongo 3.2
-00285df0df87
-f753707788c5 ubuntu 18.04
-f753707788c5 ubuntu latest
-1e0c3dd64ccd ubuntu 14.04
-```
-
-## 删除本地镜像
-
-如果要删除本地的镜像,可以使用 `docker image rm` 命令,其格式为:
-
-```
-$ docker image rm [选项] <镜像1> [<镜像2> ...]
-```
-
-### 用 ID、镜像名、摘要删除镜像
-
-其中,`<镜像>` 可以是 `镜像短 ID`、`镜像长 ID`、`镜像名` 或者 `镜像摘要`。
-
-比如我们有这么一些镜像:
-
-```bash
-$ docker image ls
-REPOSITORY TAG IMAGE ID CREATED SIZE
-centos latest 0584b3d2cf6d 3 weeks ago 196.5 MB
-redis alpine 501ad78535f0 3 weeks ago 21.03 MB
-docker latest cf693ec9b5c7 3 weeks ago 105.1 MB
-nginx latest e43d811ce2f4 5 weeks ago 181.5 MB
-```
-
-我们可以用镜像的完整 ID,也称为 `长 ID`,来删除镜像。使用脚本的时候可能会用长 ID,但是人工输入就太累了,所以更多的时候是用 `短 ID` 来删除镜像。`docker image ls` 默认列出的就已经是短 ID 了,一般取前3个字符以上,只要足够区分于别的镜像就可以了。
-
-比如这里,如果我们要删除 `redis:alpine` 镜像,可以执行:
-
-```bash
-$ docker image rm 501
-Untagged: redis:alpine
-Untagged: redis@sha256:f1ed3708f538b537eb9c2a7dd50dc90a706f7debd7e1196c9264edeea521a86d
-Deleted: sha256:501ad78535f015d88872e13fa87a828425117e3d28075d0c117932b05bf189b7
-Deleted: sha256:96167737e29ca8e9d74982ef2a0dda76ed7b430da55e321c071f0dbff8c2899b
-Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23
-Deleted: sha256:127227698ad74a5846ff5153475e03439d96d4b1c7f2a449c7a826ef74a2d2fa
-Deleted: sha256:1333ecc582459bac54e1437335c0816bc17634e131ea0cc48daa27d32c75eab3
-Deleted: sha256:4fc455b921edf9c4aea207c51ab39b10b06540c8b4825ba57b3feed1668fa7c7
-```
-
-我们也可以用`镜像名`,也就是 `<仓库名>:<标签>`,来删除镜像。
-
-```bash
-$ docker image rm centos
-Untagged: centos:latest
-Untagged: centos@sha256:b2f9d1c0ff5f87a4743104d099a3d561002ac500db1b9bfa02a783a46e0d366c
-Deleted: sha256:0584b3d2cf6d235ee310cf14b54667d889887b838d3f3d3033acd70fc3c48b8a
-Deleted: sha256:97ca462ad9eeae25941546209454496e1d66749d53dfa2ee32bf1faabd239d38
-```
-
-当然,更精确的是使用 `镜像摘要` 删除镜像。
-
-```bash
-$ docker image ls --digests
-REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
-node slim sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228 6e0c4c8e3913 3 weeks ago 214 MB
-
-$ docker image rm node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
-Untagged: node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
-```
-
-### Untagged 和 Deleted
-
-如果观察上面这几个命令的运行输出信息的话,你会注意到删除行为分为两类,一类是 `Untagged`,另一类是 `Deleted`。我们之前介绍过,镜像的唯一标识是其 ID 和摘要,而一个镜像可以有多个标签。
-
-因此当我们使用上面命令删除镜像的时候,实际上是在要求删除某个标签的镜像。所以首先需要做的是将满足我们要求的所有镜像标签都取消,这就是我们看到的 `Untagged` 的信息。因为一个镜像可以对应多个标签,因此当我们删除了所指定的标签后,可能还有别的标签指向了这个镜像,如果是这种情况,那么 `Delete` 行为就不会发生。所以并非所有的 `docker image rm`都会产生删除镜像的行为,有可能仅仅是取消了某个标签而已。
-
-当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。镜像是多层存储结构,因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变动非常容易,因此很有可能某个其它镜像正依赖于当前镜像的某一层。这种情况,依旧不会触发删除该层的行为。直到没有任何层依赖当前层时,才会真实的删除当前层。这就是为什么,有时候会奇怪,为什么明明没有别的标签指向这个镜像,但是它还是存在的原因,也是为什么有时候会发现所删除的层数和自己 `docker pull` 看到的层数不一样的源。
-
-除了镜像依赖以外,还需要注意的是容器对镜像的依赖。如果有用这个镜像启动的容器存在(即使容器没有运行),那么同样不可以删除这个镜像。之前讲过,容器是以镜像为基础,再加一层容器存储层,组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的,那么删除必然会导致故障。如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像。
-
-### 用 docker image ls 命令来配合
-
-像其它可以承接多个实体的命令一样,可以使用 `docker image ls -q` 来配合使用 `docker image rm`,这样可以成批的删除希望删除的镜像。我们在“镜像列表”章节介绍过很多过滤镜像列表的方式都可以拿过来使用。
-
-比如,我们需要删除所有仓库名为 `redis` 的镜像:
-
-```bash
-$ docker image rm $(docker image ls -q redis)
-```
-
-或者删除所有在 `mongo:3.2` 之前的镜像:
-
-```bash
-$ docker image rm $(docker image ls -q -f before=mongo:3.2)
-```
-
-充分利用你的想象力和 Linux 命令行的强大,你可以完成很多非常赞的功能。
-
-### CentOS/RHEL 的用户需要注意的事项
-
-在 Ubuntu/Debian 上有 `UnionFS` 可以使用,如 `aufs` 或者 `overlay2`,而 CentOS 和 RHEL 的内核中没有相关驱动。因此对于这类系统,一般使用 `devicemapper` 驱动利用 LVM 的一些机制来模拟分层存储。这样的做法除了性能比较差外,稳定性一般也不好,而且配置相对复杂。Docker 安装在 CentOS/RHEL 上后,会默认选择 `devicemapper`,但是为了简化配置,其 `devicemapper`是跑在一个稀疏文件模拟的块设备上,也被称为 `loop-lvm`。这样的选择是因为不需要额外配置就可以运行 Docker,这是自动配置唯一能做到的事情。但是 `loop-lvm` 的做法非常不好,其稳定性、性能更差,无论是日志还是 `docker info` 中都会看到警告信息。官方文档有明确的文章讲解了如何配置块设备给 `devicemapper` 驱动做存储层的做法,这类做法也被称为配置 `direct-lvm`。
-
-除了前面说到的问题外,`devicemapper` + `loop-lvm` 还有一个缺陷,因为它是稀疏文件,所以它会不断增长。用户在使用过程中会注意到 `/var/lib/docker/devicemapper/devicemapper/data` 不断增长,而且无法控制。很多人会希望删除镜像或者可以解决这个问题,结果发现效果并不明显。原因就是这个稀疏文件的空间释放后基本不进行垃圾回收的问题。因此往往会出现即使删除了文件内容,空间却无法回收,随着使用这个稀疏文件一直在不断增长。
-
-所以对于 CentOS/RHEL 的用户来说,在没有办法使用 `UnionFS` 的情况下,一定要配置 `direct-lvm` 给 `devicemapper`,无论是为了性能、稳定性还是空间利用率。
-
-*或许有人注意到了 CentOS 7 中存在被 backports 回来的 overlay 驱动,不过 CentOS 里的这个驱动达不到生产环境使用的稳定程度,所以不推荐使用。*
-
-## 使用 Dockerfile 定制镜像
-
-从刚才的 `docker commit` 的学习中,我们可以了解到,镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
-
-Dockerfile 是一个文本文件,其内包含了一条条的**指令(Instruction)**,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
-
-还以之前定制 `nginx` 镜像为例,这次我们使用 Dockerfile 来定制。
-
-在一个空白目录中,建立一个文本文件,并命名为 `Dockerfile`:
-
-```bash
-$ mkdir mynginx
-$ cd mynginx
-$ touch Dockerfile
-```
-
-其内容为:
-
-```dockerfile
-FROM nginx
-RUN echo 'Hello, Docker! ' > /usr/share/nginx/html/index.html
-```
-
-这个 Dockerfile 很简单,一共就两行。涉及到了两条指令,`FROM` 和 `RUN`。
-
-### 构建镜像
-
-好了,让我们再回到之前定制的 nginx 镜像的 Dockerfile 来。现在我们明白了这个 Dockerfile 的内容,那么让我们来构建这个镜像吧。
-
-在 `Dockerfile` 文件所在目录执行:
-
-```bash
-$ docker build -t nginx:v3 .
-Sending build context to Docker daemon 2.048 kB
-Step 1 : FROM nginx
- ---> e43d811ce2f4
-Step 2 : RUN echo 'Hello, Docker! ' > /usr/share/nginx/html/index.html
- ---> Running in 9cdc27646c7b
- ---> 44aa4490ce2c
-Removing intermediate container 9cdc27646c7b
-Successfully built 44aa4490ce2c
-```
-
-从命令的输出结果中,我们可以清晰的看到镜像的构建过程。在 `Step 2` 中,如同我们之前所说的那样,`RUN` 指令启动了一个容器 `9cdc27646c7b`,执行了所要求的命令,并最后提交了这一层 `44aa4490ce2c`,随后删除了所用到的这个容器 `9cdc27646c7b`。
-
-这里我们使用了 `docker build` 命令进行镜像构建。其格式为:
-
-```bash
-docker build [选项] <上下文路径/URL/->
-```
-
-在这里我们指定了最终镜像的名称 `-t nginx:v3`,构建成功后,我们可以像之前运行 `nginx:v2` 那样来运行这个镜像,其结果会和 `nginx:v2` 一样。
-
-### 镜像构建上下文(Context)
-
-如果注意,会看到 `docker build` 命令最后有一个 `.`。`.` 表示当前目录,而 `Dockerfile` 就在当前目录,因此不少初学者以为这个路径是在指定 `Dockerfile` 所在路径,这么理解其实是不准确的。如果对应上面的命令格式,你可能会发现,这是在指定**上下文路径**。那么什么是上下文呢?
-
-首先我们要理解 `docker build` 的工作原理。Docker 在运行时分为 Docker 引擎(也就是服务端守护进程)和客户端工具。Docker 的引擎提供了一组 REST API,被称为 [Docker Remote API](https://docs.docker.com/engine/reference/api/docker_remote_api/),而如 `docker` 命令这样的客户端工具,则是通过这组 API 与 Docker 引擎交互,从而完成各种功能。因此,虽然表面上我们好像是在本机执行各种 `docker` 功能,但实际上,一切都是使用的远程调用形式在服务端(Docker 引擎)完成。也因为这种 C/S 设计,让我们操作远程服务器的 Docker 引擎变得轻而易举。
-
-当我们进行镜像构建的时候,并非所有定制都会通过 `RUN` 指令完成,经常会需要将一些本地文件复制进镜像,比如通过 `COPY` 指令、`ADD` 指令等。而 `docker build` 命令构建镜像,其实并非在本地构建,而是在服务端,也就是 Docker 引擎中构建的。那么在这种客户端/服务端的架构中,如何才能让服务端获得本地文件呢?
-
-这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径,`docker build` 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。
-
-如果在 `Dockerfile` 中这么写:
-
-```Dockerfile
-COPY ./package.json /app/
-```
-
-这并不是要复制执行 `docker build` 命令所在的目录下的 `package.json`,也不是复制 `Dockerfile` 所在目录下的 `package.json`,而是复制 **上下文(context)** 目录下的 `package.json`。
-
-因此,`COPY` 这类指令中的源文件的路径都是*相对路径*。这也是初学者经常会问的为什么 `COPY ../package.json /app` 或者 `COPY /opt/xxxx /app` 无法工作的原因,因为这些路径已经超出了上下文的范围,Docker 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去。
-
-现在就可以理解刚才的命令 `docker build -t nginx:v3 .` 中的这个 `.`,实际上是在指定上下文的目录,`docker build` 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。
-
-如果观察 `docker build` 输出,我们其实已经看到了这个发送上下文的过程:
-
-```bash
-$ docker build -t nginx:v3 .
-Sending build context to Docker daemon 2.048 kB
-...
-```
-
-理解构建上下文对于镜像构建是很重要的,避免犯一些不应该的错误。比如有些初学者在发现 `COPY /opt/xxxx /app` 不工作后,于是干脆将 `Dockerfile` 放到了硬盘根目录去构建,结果发现 `docker build` 执行后,在发送一个几十 GB 的东西,极为缓慢而且很容易构建失败。那是因为这种做法是在让 `docker build`打包整个硬盘,这显然是使用错误。
-
-一般来说,应该会将 `Dockerfile` 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 `.gitignore` 一样的语法写一个 `.dockerignore`,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。
-
-那么为什么会有人误以为 `.` 是指定 `Dockerfile` 所在目录呢?这是因为在默认情况下,如果不额外指定 `Dockerfile` 的话,会将上下文目录下的名为 `Dockerfile` 的文件作为 Dockerfile。
-
-这只是默认行为,实际上 `Dockerfile` 的文件名并不要求必须为 `Dockerfile`,而且并不要求必须位于上下文目录中,比如可以用 `-f ../Dockerfile.php` 参数指定某个文件作为 `Dockerfile`。
-
-当然,一般大家习惯性的会使用默认的文件名 `Dockerfile`,以及会将其置于镜像构建上下文目录中。
-
-### 其它 `docker build` 的用法
-
-#### 直接用 Git repo 进行构建
-
-或许你已经注意到了,`docker build` 还支持从 URL 构建,比如可以直接从 Git repo 中构建:
-
-```bash
-$ docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14
-docker build https://github.com/twang2218/gitlab-ce-zh.git\#:8.14
-Sending build context to Docker daemon 2.048 kB
-Step 1 : FROM gitlab/gitlab-ce:8.14.0-ce.0
-8.14.0-ce.0: Pulling from gitlab/gitlab-ce
-aed15891ba52: Already exists
-773ae8583d14: Already exists
-...
-```
-
-这行命令指定了构建所需的 Git repo,并且指定默认的 `master` 分支,构建目录为 `/8.14/`,然后 Docker 就会自己去 `git clone` 这个项目、切换到指定分支、并进入到指定目录后开始构建。
-
-#### 用给定的 tar 压缩包构建
-
-```bash
-$ docker build http://server/context.tar.gz
-```
-
-如果所给出的 URL 不是个 Git repo,而是个 `tar` 压缩包,那么 Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。
-
-#### 从标准输入中读取 Dockerfile 进行构建
-
-```bash
-docker build - < Dockerfile
-```
-
-或
-
-```bash
-cat Dockerfile | docker build -
-```
-
-如果标准输入传入的是文本文件,则将其视为 `Dockerfile`,并开始构建。这种形式由于直接从标准输入中读取 Dockerfile 的内容,它没有上下文,因此不可以像其他方法那样可以将本地文件 `COPY` 进镜像之类的事情。
-
-#### 从标准输入中读取上下文压缩包进行构建
-
-```bash
-$ docker build - < context.tar.gz
-```
-
-如果发现标准输入的文件格式是 `gzip`、`bzip2` 以及 `xz` 的话,将会使其为上下文压缩包,直接将其展开,将里面视为上下文,并开始构建。
diff --git a/docs/docker/basics/docker-repository.md b/docs/docker/basics/docker-repository.md
deleted file mode 100644
index 5c6a7bdf..00000000
--- a/docs/docker/basics/docker-repository.md
+++ /dev/null
@@ -1,100 +0,0 @@
-# Docker 仓库
-
-仓库(Repository)是集中存放镜像的地方。
-
-一个容易混淆的概念是注册服务器(Registry)。实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。从这方面来说,仓库可以被认为是一个具体的项目或目录。例如对于仓库地址 dl.dockerpool.com/ubuntu 来说,dl.dockerpool.com 是注册服务器地址,ubuntu 是仓库名。
-
-## Docker Hub
-
-目前 Docker 官方维护了一个公共仓库 [Docker Hub](https://hub.docker.com/),其中已经包括了数量超过 15,000 的镜像。大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。
-
-### 注册
-
-你可以在 [https://cloud.docker.com](https://cloud.docker.com/) 免费注册一个 Docker 账号。
-
-### 登录
-
-可以通过执行 `docker login` 命令交互式的输入用户名及密码来完成在命令行界面登录 Docker Hub。
-
-你可以通过 `docker logout` 退出登录。
-
-### 拉取镜像
-
-你可以通过 `docker search` 命令来查找官方仓库中的镜像,并利用 `docker pull` 命令来将它下载到本地。
-
-例如以 `centos` 为关键词进行搜索:
-
-```bash
-$ docker search centos
-NAME DESCRIPTION STARS OFFICIAL AUTOMATED
-centos The official build of CentOS. 465 [OK]
-tianon/centos CentOS 5 and 6, created using rinse instea... 28
-blalor/centos Bare-bones base CentOS 6.5 image 6 [OK]
-saltstack/centos-6-minimal 6 [OK]
-tutum/centos-6.4 DEPRECATED. Use tutum/centos:6.4 instead. ... 5 [OK]
-```
-
-可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、收藏数(表示该镜像的受关注程度)、是否官方创建、是否自动创建。
-
-官方的镜像说明是官方项目组创建和维护的,automated 资源允许用户验证镜像的来源和内容。
-
-根据是否是官方提供,可将镜像资源分为两类。
-
-一种是类似 `centos` 这样的镜像,被称为基础镜像或根镜像。这些基础镜像由 Docker 公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字。
-
-还有一种类型,比如 `tianon/centos` 镜像,它是由 Docker 的用户创建并维护的,往往带有用户名称前缀。可以通过前缀 `username/` 来指定使用某个用户提供的镜像,比如 tianon 用户。
-
-另外,在查找的时候通过 `--filter=stars=N` 参数可以指定仅显示收藏数量为 `N` 以上的镜像。
-
-下载官方 `centos` 镜像到本地。
-
-```bash
-$ docker pull centos
-Pulling repository centos
-0b443ba03958: Download complete
-539c0211cd76: Download complete
-511136ea3c5a: Download complete
-7064731afe90: Download complete
-```
-
-### 推送镜像
-
-用户也可以在登录后通过 `docker push` 命令来将自己的镜像推送到 Docker Hub。
-
-以下命令中的 `username` 请替换为你的 Docker 账号用户名。
-
-```bash
-$ docker tag ubuntu:18.04 username/ubuntu:18.04
-
-$ docker image ls
-
-REPOSITORY TAG IMAGE ID CREATED SIZE
-ubuntu 18.04 275d79972a86 6 days ago 94.6MB
-username/ubuntu 18.04 275d79972a86 6 days ago 94.6MB
-
-$ docker push username/ubuntu:18.04
-
-$ docker search username
-
-NAME DESCRIPTION STARS OFFICIAL AUTOMATED
-username/ubuntu
-```
-
-### 自动创建
-
-自动创建(Automated Builds)功能对于需要经常升级镜像内程序来说,十分方便。
-
-有时候,用户创建了镜像,安装了某个软件,如果软件发布新版本则需要手动更新镜像。
-
-而自动创建允许用户通过 Docker Hub 指定跟踪一个目标网站(目前支持 [GitHub](https://github.com/) 或 [BitBucket](https://bitbucket.org/))上的项目,一旦项目发生新的提交或者创建新的标签(tag),Docker Hub 会自动构建镜像并推送到 Docker Hub 中。
-
-要配置自动创建,包括如下的步骤:
-
-- 创建并登录 Docker Hub,以及目标网站;
-- 在目标网站中连接帐户到 Docker Hub;
-- 在 Docker Hub 中 [配置一个自动创建](https://registry.hub.docker.com/builds/add/);
-- 选取一个目标网站中的项目(需要含 `Dockerfile`)和分支;
-- 指定 `Dockerfile` 的位置,并提交创建。
-
-之后,可以在 Docker Hub 的 [自动创建页面](https://registry.hub.docker.com/builds/) 中跟踪每次创建的状态。
-
diff --git a/docs/docker/basics/docker-services.md b/docs/docker/basics/docker-services.md
deleted file mode 100644
index 392d3268..00000000
--- a/docs/docker/basics/docker-services.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# Docker 服务
-
-## 关于服务
-
-在分布式应用程序中,应用程序的不同部分被称为“服务”。例如,如果您想象一个视频共享网站,它可能包含用于将应用程序数据存储在数据库中的服务,用户上传文件后在后台传输的服务,前端应用服务等等。
-
-服务实际上只是“生产环境中的容器”。一个服务只运行一个镜像,但它需要制定镜像的运行方式 - 应该使用哪个端口,容器应该运行多少副本,以便服务具有所需的容量,以及等等。缩放服务会更改运行该软件的容器实例的数量,从而为流程中的服务分配更多计算资源。
-
-幸运的是,使用 Docker 平台定义,运行和扩展服务非常简单 - 只需编写一个 docker-compose.yml 文件即可。
-
-## docker-compose.yml 文件
-
-它是一个YAML文件,它定义了Docker容器在生产中的行为方式。
-
-
-```
-version: "3"
-services:
- web:
- # replace username/repo:tag with your name and image details
- image: username/repo:tag
- deploy:
- replicas: 5
- resources:
- limits:
- cpus: "0.1"
- memory: 50M
- restart_policy:
- condition: on-failure
- ports:
- - "80:80"
- networks:
- - webnet
-networks:
- webnet:
-```
diff --git a/docs/docker/docker-cheat-sheet.md b/docs/docker/docker-cheat-sheet.md
index 58f27ade..f3ad99d1 100644
--- a/docs/docker/docker-cheat-sheet.md
+++ b/docs/docker/docker-cheat-sheet.md
@@ -4,6 +4,8 @@
+- [为何使用 Docker](#为何使用-docker)
+- [运维](#运维)
- [容器(Container)](#容器container)
- [镜像(Images)](#镜像images)
- [网络(Networks)](#网络networks)
@@ -20,9 +22,89 @@
+## 为何使用 Docker
+
+「通过 Docker,开发者可以使用任何语言任何工具创建任何应用。“Dockerized” 的应用是完全可移植的,能在任何地方运行 - 不管是同事的 OS X 和 Windows 笔记本,或是在云端运行的 Ubuntu QA 服务,还是在虚拟机运行的 Red Hat 产品数据中心。
+
+Docker Hub 上有 13000+ 的应用,开发者可以从中选取一个进行快速扩展开发。Docker 跟踪管理变更和依赖关系,让系统管理员能更容易理解开发人员是如何让应用运转起来的。而开发者可以通过 Docker Hub 的共有/私有仓库,构建他们的自动化编译,与其他合作者共享成果。
+
+Docker 帮助开发者更快地构建和发布高质量的应用。」—— [什么是 Docker](https://www.docker.com/what-docker/#copy1)
+
+## 运维
+
+### 安装
+
+Docker 是一个开源的商业产品,有两个版本:社区版(Community Edition,缩写为 CE)和企业版(Enterprise Edition,缩写为 EE)。企业版包含了一些收费服务,个人开发者一般用不到。
+
+Docker CE 的安装请参考官方文档。
+
+- [Mac](https://docs.docker.com/docker-for-mac/install/)
+- [Windows](https://docs.docker.com/docker-for-windows/install/)
+- [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/)
+- [Debian](https://docs.docker.com/install/linux/docker-ce/debian/)
+- [CentOS](https://docs.docker.com/install/linux/docker-ce/centos/)
+- [Fedora](https://docs.docker.com/install/linux/docker-ce/fedora/)
+- [其他 Linux 发行版](https://docs.docker.com/install/linux/docker-ce/binaries/)
+
+### 检查版本
+
+[`docker version`](https://docs.docker.com/engine/reference/commandline/version/) 查看你正在运行的 Docker 版本。
+
+获取 Docker 服务版本:
+
+```
+docker version --format '{{.Server.Version}}'
+```
+
+你也可以输出原始的 JSON 数据:
+
+```
+docker version --format '{{json .}}'
+```
+
+### Docker 加速
+
+国内访问 Docker Hub 很慢,所以,推荐配置 Docker 镜像仓库来提速。
+
+镜像仓库清单:
+
+| 镜像仓库 | 镜像仓库地址 | 说明 |
+| --------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [DaoCloud 镜像站](https://daocloud.io/mirror) | `http://f1361db2.m.daocloud.io` | 开发者需要开通 DaoCloud 账户,然后可以得到专属加速器。 |
+| [阿里云](https://cr.console.aliyun.com) | `https://yourcode.mirror.aliyuncs.com` | 开发者需要开通阿里开发者帐户,再使用阿里的加速服务。登录后阿里开发者帐户后,`https://cr.console.aliyun.com/undefined/instances/mirrors` 中查看你的您的专属加速器地址。 |
+| [网易云](https://c.163yun.com/hub) | `https://hub-mirror.c.163.com` | 直接配置即可,亲测较为稳定。 |
+
+配置镜像仓库方法(以 CentOS 为例):
+
+> 下面的示例为在 CentOS 环境中,指定镜像仓库为 `https://hub-mirror.c.163.com`
+
+(1)修改配置文件
+
+修改 `/etc/docker/daemon.json` ,如果不存在则新建。执行以下 Shell:
+
+```bash
+sudo mkdir -p /etc/docker
+cat >> /etc/docker/daemon.json << EOF
+{
+ "registry-mirrors": [
+ "https://hub-mirror.c.163.com"
+ ]
+}
+EOF
+```
+
+重启 docker 以生效:
+
+```bash
+sudo systemctl daemon-reload
+sudo systemctl restart docker
+```
+
+执行 `docker info` 命令,查看 `Registry Mirrors` 是否已被改为 `https://hub-mirror.c.163.com` ,如果是,则表示配置成功。
+
## 容器(Container)
-[关于 Docker 进程隔离的基础](http://etherealmind.com/basics-docker-containers-hypervisors-coreos/)。容器 (Container) 之于虚拟机 (Virtual Machine) 就好比线程之于进程。
+[关于 Docker 进程隔离的基础](http://etherealmind.com/basics-docker-containers-hypervisors-coreos/)。容器 (Container) 之于虚拟机 (Virtual Machine) 就好比线程之于进程。或者你可以把他们想成是「吃了类固醇的 chroots」。
### 生命周期
@@ -32,13 +114,13 @@
- [`docker rm`](https://docs.docker.com/engine/reference/commandline/rm) 删除容器。
- 如果要删除一个运行中的容器,可以添加 `-f` 参数。Docker 会发送 `SIGKILL` 信号给容器。
- [`docker update`](https://docs.docker.com/engine/reference/commandline/update/) 调整容器的资源限制。
-- `docker container prune` 清理掉所有处于终止状态的容器。
+- 清理掉所有处于终止状态的容器。
通常情况下,不使用任何命令行选项启动一个容器,该容器将会立即启动并停止。若需保持其运行,你可以使用 `docker run -td container_id` 命令。选项 `-t` 表示分配一个 pseudo-TTY 会话,`-d` 表示自动将容器与终端分离(也就是说在后台运行容器,并输出容器 ID)。
如果你需要一个临时容器,可使用 `docker run --rm` 会在容器停止之后删除它。
-如果你需要映射宿主机 (host) 的目录到 Docker 容器内,可使用 `docker run -v $HOSTDIR:$DOCKERDIR`。详见 [卷标(Volumes)](#卷标volumes) 一节。
+如果你需要映射宿主机 (host) 的目录到 Docker 容器内,可使用 `docker run -v $HOSTDIR:$DOCKERDIR`。详见 [卷标(Volumes)](https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn#卷标volumes) 一节。
如果你想同时删除与容器相关联的卷标,那么在删除容器的时候必须包含 `-v` 选项,像这样 `docker rm -v`。
@@ -55,7 +137,7 @@
- [`docker kill`](https://docs.docker.com/engine/reference/commandline/kill) 向运行中的容器发送 SIGKILL 指令。
- [`docker attach`](https://docs.docker.com/engine/reference/commandline/attach) 连接到运行中的容器。
-如果你想将容器的端口 (ports) 暴露至宿主机,请见 [暴露端口](#暴露端口exposing-ports) 一节。
+如果你想将容器的端口 (ports) 暴露至宿主机,请见 [暴露端口](https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn#暴露端口exposing-ports) 一节。
关于 Docker 实例崩溃后的重启策略,详见 [本文](http://container42.com/2014/09/30/docker-restart-policies/)。
@@ -69,7 +151,7 @@
docker run -ti --c 512 agileek/cpuset-test
```
-更多信息请参阅 。
+更多信息请参阅 https://goldmann.pl/blog/2014/09/11/resource-management-in-docker/#_cpu。
通过 [`cpuset-cpus`](https://docs.docker.com/engine/reference/run/#/cpuset-constraint) 可使用特定 CPU 内核。
@@ -77,9 +159,9 @@ docker run -ti --c 512 agileek/cpuset-test
docker run -ti --cpuset-cpus=0,4,6 agileek/cpuset-test
```
-请参阅 获取更多细节以及一些不错的视频。
+请参阅 https://agileek.github.io/docker/2014/08/06/docker-cpuset/ 获取更多细节以及一些不错的视频。
-注意,Docker 在容器内仍然能够 **看到** 全部 CPU -- 它仅仅是不使用全部而已。请参阅 获取更多细节。
+注意,Docker 在容器内仍然能够 **看到** 全部 CPU -- 它仅仅是不使用全部而已。请参阅 https://github.com/docker/docker/issues/20770 获取更多细节。
#### 内存限制
@@ -91,7 +173,7 @@ docker run -it -m 300M ubuntu:14.04 /bin/bash
#### 能力(Capabilities)
-Linux 的 Capability 可以通过使用 `cap-add` 和 `cap-drop` 设置。请参阅 获取更多细节。这有助于提高安全性。
+Linux 的 Capability 可以通过使用 `cap-add` 和 `cap-drop` 设置。请参阅 https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities 获取更多细节。这有助于提高安全性。
如需要挂载基于 FUSE 的文件系统,你需要结合 `--cap-add` 和 `--device` 使用:
@@ -136,7 +218,8 @@ docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash
### 执行命令
- [`docker exec`](https://docs.docker.com/engine/reference/commandline/exec) 在容器内执行命令。
- - 例如,进入正在运行的 `foo` 容器,并连接 (attach) 到一个新的 Shell 进程:`docker exec -it foo /bin/bash`。
+
+例如,进入正在运行的 `foo` 容器,并连接 (attach) 到一个新的 Shell 进程:`docker exec -it foo /bin/bash`。
## 镜像(Images)
@@ -159,7 +242,7 @@ docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash
### 清理
-虽然你可以用 `docker rmi` 命令来删除指定的镜像,不过有个名为 [docker-gc](https://github.com/spotify/docker-gc) 的工具,它可以以一种安全的方式,清理掉那些不再被任何容器使用的镜像。Docker 1.13 起,使用 `docker image prune` 亦可删除未使用的镜像。参见 [清理](#清理)。
+虽然你可以用 `docker rmi` 命令来删除指定的镜像,不过有个名为 [docker-gc](https://github.com/spotify/docker-gc) 的工具,它可以以一种安全的方式,清理掉那些不再被任何容器使用的镜像。Docker 1.13 起,使用 `docker image prune` 亦可删除未使用的镜像。参见 [清理](https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn#清理)。
### 加载 / 保存镜像
@@ -191,8 +274,7 @@ docker export my_container | gzip > my_container.tar.gz
### 加载已保存的镜像 与 导入已导出为镜像的容器 的不同
-通过 `load` 命令来加载镜像,会创建一个新的镜像,并继承原镜像的所有历史。
-通过 `import` 将容器作为镜像导入,也会创建一个新的镜像,但并不包含原镜像的历史,因此会比使用 `load` 方式生成的镜像更小。
+通过 `load` 命令来加载镜像,会创建一个新的镜像,并继承原镜像的所有历史。 通过 `import` 将容器作为镜像导入,也会创建一个新的镜像,但并不包含原镜像的历史,因此会比使用 `load` 方式生成的镜像更小。
## 网络(Networks)
@@ -226,6 +308,48 @@ $ docker run --rm -it --net iptastic --ip 203.0.113.2 nginx
$ curl 203.0.113.2
```
+## 暴露端口(Exposing ports)
+
+通过宿主容器暴露输入端口相当 [繁琐但有效的](https://docs.docker.com/engine/reference/run/#expose-incoming-ports)。
+
+例如使用 `-p` 将容器端口映射到宿主端口上(只使用本地主机 (localhost) 接口):
+
+```
+docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage
+```
+
+你可以使用 [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) 告知 Docker,该容器在运行时监听指定的端口:
+
+```
+EXPOSE
+```
+
+但是注意 EXPOSE 并不会直接暴露端口,你需要用参数 `-p` 。比如说你要在 localhost 上暴露容器的端口:
+
+```
+iptables -t nat -A DOCKER -p tcp --dport -j DNAT --to-destination :
+```
+
+如果你是在 Virtualbox 中运行 Docker,那么你需要配置端口转发 (forward the port)。使用 [forwarded_port](https://docs.vagrantup.com/v2/networking/forwarded_ports.html) 在 Vagrantfile 上配置暴露的端口范围,这样你就可以动态地映射了:
+
+```
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+ ...
+
+ (49000..49900).each do |port|
+ config.vm.network :forwarded_port, :host => port, :guest => port
+ end
+
+ ...
+end
+```
+
+如果你忘记了将什么端口映射到宿主机上的话,可使用 `docker port` 查看:
+
+```
+docker port CONTAINER $CONTAINERPORT
+```
+
## 仓管中心和仓库(Registry & Repository)
仓库 (repository) 是 _被托管(hosted)_ 的已命名镜像 (tagged images) 的集合,这组镜像用于构建容器文件系统。
@@ -252,8 +376,8 @@ Docker 官方托管着自己的 [仓管中心](https://hub.docker.com/),包含
以下是一些编写 Dockerfile 的常用编辑器,并链接到适配的语法高亮模块︰
-- 如果你在使用 [jEdit](http://jedit.org),你可以使用我开发的 Dockerfile [语法高亮模块](https://github.com/wsargent/jedit-docker-mode)。
-- [Sublime Text 2](https://packagecontrol.io/packages/Dockerfile%20Syntax%20Highlighting)
+- 如果你在使用 [jEdit](http://jedit.org/),你可以使用我开发的 Dockerfile [语法高亮模块](https://github.com/wsargent/jedit-docker-mode)。
+- [Sublime Text 2](https://packagecontrol.io/packages/Dockerfile Syntax Highlighting)
- [Atom](https://atom.io/packages/language-docker)
- [Vim](https://github.com/ekalinin/Dockerfile.vim)
- [Emacs](https://github.com/spotify/dockerfile-mode)
@@ -329,19 +453,27 @@ $ALIAS_PORT_1337_TCP_ADDR
通常,Docker 容器(亦可理解为「服务」)之间的链接,是「服务发现」的一个子集。如果你打算在生产中大规模使用 Docker,这将是一个很大的问题。请参阅[The Docker Ecosystem: Service Discovery and Distributed Configuration Stores](https://www.digitalocean.com/community/tutorials/the-docker-ecosystem-service-discovery-and-distributed-configuration-stores) 获取更多信息。
-## 卷标(Volumes)
+## 卷标(Volumes)和挂载
+
+### 卷标
Docker 的卷标 (volumes) 是 [独立的文件系统](https://docs.docker.com/engine/tutorials/dockervolumes/)。它们并非必须连接到特定的容器上。
-### 生命周期
+`数据卷` 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
-- [`docker volume create`](https://docs.docker.com/engine/reference/commandline/volume_create/)
-- [`docker volume rm`](https://docs.docker.com/engine/reference/commandline/volume_rm/)
+- `数据卷` 可以在容器之间共享和重用
+- 对 `数据卷` 的修改会立马生效
+- 对 `数据卷` 的更新,不会影响镜像
+- `数据卷` 默认会一直存在,即使容器被删除
-### 信息
+卷标相关命令:
+
+- [`docker volume create`](https://docs.docker.com/engine/reference/commandline/volume_create/) - 创建卷标
+- [`docker volume rm`](https://docs.docker.com/engine/reference/commandline/volume_rm/) - 删除卷标
-- [`docker volume ls`](https://docs.docker.com/engine/reference/commandline/volume_ls/)
-- [`docker volume inspect`](https://docs.docker.com/engine/reference/commandline/volume_inspect/)
+- [`docker volume ls`](https://docs.docker.com/engine/reference/commandline/volume_ls/) - 查看卷标
+- [`docker volume inspect`](https://docs.docker.com/engine/reference/commandline/volume_inspect/) - 查看数据卷的具体信息
+- [`docker volume prune`](https://docs.docker.com/engine/reference/commandline/volume_prune/) - 清理无主的数据卷
卷标在不能使用链接(只有 TCP/IP)的情况下非常有用。例如,如果你有两个 Docker 实例需要通讯并在文件系统上留下记录。
@@ -361,49 +493,13 @@ docker run -v /Users/wsargent/myapp/src:/src
还可以考虑运行一个纯数据容器,像 [这里](http://container42.com/2013/12/16/persistent-volumes-with-docker-container-as-volume-pattern/) 所说的那样,提供可移植数据。
-记得,[文件也可以被挂载为卷标](#将文件挂载为卷标)。
+记得,[文件也可以被挂载为卷标](https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn#将文件挂载为卷标)。
-## 暴露端口(Exposing ports)
+### 挂载
-通过宿主容器暴露输入端口相当 [繁琐但有效的](https://docs.docker.com/engine/reference/run/#expose-incoming-ports)。
+使用 `--mount` 标记可以指定挂载一个本地主机的目录到容器中去。
-例如使用 `-p` 将容器端口映射到宿主端口上(只使用本地主机 (localhost) 接口):
-
-```
-docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage
-```
-
-你可以使用 [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) 告知 Docker,该容器在运行时监听指定的端口:
-
-```
-EXPOSE
-```
-
-但是注意 EXPOSE 并不会直接暴露端口,你需要用参数 `-p` 。比如说你要在 localhost 上暴露容器的端口:
-
-```
-iptables -t nat -A DOCKER -p tcp --dport -j DNAT --to-destination :
-```
-
-如果你是在 Virtualbox 中运行 Docker,那么你需要配置端口转发 (forward the port)。使用 [forwarded_port](https://docs.vagrantup.com/v2/networking/forwarded_ports.html) 在 Vagrantfile 上配置暴露的端口范围,这样你就可以动态地映射了:
-
-```
-Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
- ...
-
- (49000..49900).each do |port|
- config.vm.network :forwarded_port, :host => port, :guest => port
- end
-
- ...
-end
-```
-
-如果你忘记了将什么端口映射到宿主机上的话,可使用 `docker port` 查看:
-
-```
-docker port CONTAINER $CONTAINERPORT
-```
+在用 `docker run` 命令的时候,使用 `--mount` 标记来将 `数据卷` 挂载到容器里。在一次 `docker run` 中可以挂载多个 `数据卷`。
## 最佳实践
@@ -498,8 +594,7 @@ USER user
### 安全路线图
-Docker 的路线图提到关于 [seccomp 的支持](https://github.com/docker/docker/blob/master/ROADMAP.md#11-security)。
-一个名为 [bane](https://github.com/jfrazelle/bane) 的 AppArmor 策略生成器正在实现 [安全配置文件](https://github.com/docker/docker/issues/17142)。
+Docker 的路线图提到关于 [seccomp 的支持](https://github.com/docker/docker/blob/master/ROADMAP.md#11-security)。 一个名为 [bane](https://github.com/jfrazelle/bane) 的 AppArmor 策略生成器正在实现 [安全配置文件](https://github.com/docker/docker/issues/17142)。
## 小贴士
@@ -654,8 +749,7 @@ docker images -viz | dot -Tpng -o docker.png
- 在某层 (RUN layer) 清理 APT
-这应当和其他 apt 命令在同一层中完成。
-否则,前面的层将会保持原有信息,而你的镜像则依旧臃肿。
+这应当和其他 apt 命令在同一层中完成。 否则,前面的层将会保持原有信息,而你的镜像则依旧臃肿。
```
RUN {apt commands} \
diff --git a/docs/docker/docker-compose.md b/docs/docker/docker-compose.md
new file mode 100644
index 00000000..3fec8712
--- /dev/null
+++ b/docs/docker/docker-compose.md
@@ -0,0 +1,110 @@
+# Docker Compose
+
+> [compose](https://github.com/docker/compose) 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,跟 `OpenStack` 中的 `Heat` 十分类似。
+
+## 一、Compose 简介
+
+**`Compose` 的定位是:定义和运行多个 Docker 容器的应用**。 使用一个 `Dockerfile` 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。
+
+`Compose` 恰好满足了这样的需求。它允许用户通过一个单独的 `docker-compose.yml` 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
+
+`Compose` 中有两个重要的概念:
+
+- **服务 (`service`)**:一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
+- **项目 (`project`)**:由一组关联的应用容器组成的一个完整业务单元,在 `docker-compose.yml` 文件中定义。
+
+ `Compose` 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。
+
+## 二、安装卸载
+
+`Compose` 支持 Linux、macOS、Windows10 三大平台。
+
+Linux 安装方式:
+
+```bash
+sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
+sudo chmod +x /usr/local/bin/docker-compose
+```
+
+> :bell: 详情请参考:[Install Docker Compose](https://docs.docker.com/compose/install/)
+
+## 三、快速入门
+
+### web 应用
+
+新建文件夹,在该目录中编写 `app.py` 文件
+
+```python
+from flask import Flask
+from redis import Redis
+
+app = Flask(__name__)
+redis = Redis(host='redis', port=6379)
+
+@app.route('/')
+def hello():
+ count = redis.incr('hits')
+ return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
+
+if __name__ == "__main__":
+ app.run(host="0.0.0.0", debug=True)
+```
+
+### Dockerfile
+
+编写 `Dockerfile` 文件,内容为
+
+```docker
+FROM python:3.6-alpine
+ADD . /code
+WORKDIR /code
+RUN pip install redis flask
+CMD ["python", "app.py"]
+```
+
+### docker-compose.yml
+
+编写 `docker-compose.yml` 文件,这个是 Compose 使用的主模板文件。
+
+```yaml
+version: '3'
+services:
+
+ web:
+ build: .
+ ports:
+ - "5000:5000"
+
+ redis:
+ image: "redis:alpine"
+```
+
+### 运行 compose 项目
+
+```bash
+$ docker-compose up
+```
+
+此时访问本地 `5000` 端口,每次刷新页面,计数就会加 1。
+
+## 四、命令
+
+> :bell: 请参考:
+>
+> - [Compose 官方命令说明文档](https://docs.docker.com/compose/reference/)
+> - [Compose 命令说明中文文档](https://yeasy.gitbooks.io/docker_practice/content/compose/commands.html)
+
+## 五、模板文件
+
+> `docker-compose.yml` 文件是 Docker Compose 的模板文件,其作用类似于 Dockerfile 和 Docker。
+
+[docker-compose.yml 支持的默认环境变量官方文档](https://docs.docker.com/compose/env-file/)
+
+## 参考资料
+
+- **官方**
+ - [Docker Compose Github](https://github.com/docker/compose)
+ - [Docker Compose 官方文档](https://docs.docker.com/compose/)
+- **教程**
+ - [Docker — 从入门到实践 - Docker Compose 项目]( https://yeasy.gitbooks.io/docker_practice/content/compose/ )
+
diff --git a/docs/docker/basics/docker-dockerfile.md b/docs/docker/docker-dockerfile.md
similarity index 90%
rename from docs/docker/basics/docker-dockerfile.md
rename to docs/docker/docker-dockerfile.md
index 4c221540..492e092b 100644
--- a/docs/docker/basics/docker-dockerfile.md
+++ b/docs/docker/docker-dockerfile.md
@@ -1,33 +1,39 @@
-# Dockerfile
+# Dockerfile 最佳实践
-- [Dockerfile 指令](#dockerfile-指令)
- - [FROM(指定基础镜像)](#from指定基础镜像)
- - [RUN(执行命令)](#run执行命令)
- - [COPY(复制文件)](#copy复制文件)
- - [ADD(更高级的复制文件)](#add更高级的复制文件)
- - [CMD(容器启动命令)](#cmd容器启动命令)
- - [ENTRYPOINT(入口点)](#entrypoint入口点)
- - [ENV(设置环境变量)](#env设置环境变量)
- - [ARG(构建参数)](#arg构建参数)
- - [VOLUME(定义匿名卷)](#volume定义匿名卷)
- - [EXPOSE(暴露端口)](#expose暴露端口)
- - [WORKDIR(指定工作目录)](#workdir指定工作目录)
- - [USER(指定当前用户)](#user指定当前用户)
- - [HEALTHCHECK(健康检查)](#healthcheck健康检查)
- - [ONBUILD(为他人作嫁衣裳)](#onbuild为他人作嫁衣裳)
-- [引用和引申](#引用和引申)
+- [一、Dockerfile 指令](#一dockerfile-指令)
+ - [FROM(指定基础镜像)](#from指定基础镜像)
+ - [RUN(执行命令)](#run执行命令)
+ - [COPY(复制文件)](#copy复制文件)
+ - [ADD(更高级的复制文件)](#add更高级的复制文件)
+ - [CMD(容器启动命令)](#cmd容器启动命令)
+ - [ENTRYPOINT(入口点)](#entrypoint入口点)
+ - [ENV(设置环境变量)](#env设置环境变量)
+ - [ARG(构建参数)](#arg构建参数)
+ - [VOLUME(定义匿名卷)](#volume定义匿名卷)
+ - [EXPOSE(暴露端口)](#expose暴露端口)
+ - [WORKDIR(指定工作目录)](#workdir指定工作目录)
+ - [USER(指定当前用户)](#user指定当前用户)
+ - [HEALTHCHECK(健康检查)](#healthcheck健康检查)
+ - [ONBUILD(为他人作嫁衣裳)](#onbuild为他人作嫁衣裳)
+- [参考资料](#参考资料)
-## Dockerfile 指令
+## 一、Dockerfile 简介
+
+Docker 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
+
+Dockerfile 是一个文本文件,其内包含了一条条的 **指令(Instruction)**,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
+
+### 使用 Dockerfile 构建镜像
+
+## 二、Dockerfile 指令详解
### FROM(指定基础镜像)
-> 作用:
->
-> `FROM` 指令用于指定基础镜像。
+> 作用:**`FROM` 指令用于指定基础镜像**。
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 `nginx` 镜像的容器,再进行修改一样,基础镜像是必须指定的。而 `FROM` 就是指定**基础镜像**,因此一个 `Dockerfile` 中 `FROM` 是必备的指令,并且必须是第一条指令。
@@ -48,15 +54,15 @@ FROM scratch
### RUN(执行命令)
-`RUN` 指令是用来执行命令行命令的。由于命令行的强大能力,`RUN` 指令在定制镜像时是最常用的指令之一。其格式有两种:
-
-- _shell_ 格式:`RUN <命令>`,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 `RUN` 指令就是这种格式。
-
-```dockerfile
-RUN echo 'Hello, Docker! ' > /usr/share/nginx/html/index.html
-```
-
-- _exec_ 格式:`RUN ["可执行文件", "参数1", "参数2"]`,这更像是函数调用中的格式。
+> **`RUN` 指令是用来执行命令行命令的**。由于命令行的强大能力,`RUN` 指令在定制镜像时是最常用的指令之一。其格式有两种:
+>
+> - _shell_ 格式:`RUN <命令>`,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 `RUN` 指令就是这种格式。
+>
+> ```dockerfile
+> RUN echo 'Hello, Docker! ' > /usr/share/nginx/html/index.html
+> ```
+>
+> - _exec_ 格式:`RUN ["可执行文件", "参数1", "参数2"]`,这更像是函数调用中的格式。
既然 `RUN` 就像 Shell 脚本一样可以执行命令,那么我们是否就可以像 Shell 脚本一样把每个命令对应一个 RUN 呢?比如这样:
@@ -107,8 +113,6 @@ RUN buildDeps='gcc libc6-dev make' \
### COPY(复制文件)
-> 作用:
->
> **`COPY` 指令将从构建上下文目录中 `<源路径>` 的文件/目录复制到新的一层的镜像内的 `<目标路径>` 位置。**
格式:
@@ -144,8 +148,6 @@ COPY --chown=10:11 files* /mydir/
### ADD(更高级的复制文件)
-> 作用:
->
> `ADD` 指令和 `COPY` 的格式和性质基本一致。但是在 `COPY` 基础上增加了一些功能。
>
> 比如 `<源路径>` 可以是一个 `URL`,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 `<目标路径>`去。下载后的文件权限自动设置为 `600`,如果这并不是想要的权限,那么还需要增加额外的一层 `RUN` 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 `RUN` 指令进行解压缩。所以不如直接使用 `RUN` 指令,然后使用 `wget` 或者 `curl` 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。
@@ -179,8 +181,6 @@ ADD --chown=10:11 files* /mydir/
### CMD(容器启动命令)
-> 作用:
->
> 之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。`CMD` 指令就是用于指定默认的容器主进程的启动命令的。
`CMD` 指令的格式和 `RUN` 相似,也是两种格式:
@@ -356,7 +356,7 @@ uid=0(root) gid=0(root) groups=0(root)
### ENV(设置环境变量)
-> 作用:`ENV` 指令用于设置环境变量。无论是后面的其它指令,如 `RUN`,还是运行时的应用,都可以直接使用这里定义的环境变量。
+> `ENV` 指令用于设置环境变量。无论是后面的其它指令,如 `RUN`,还是运行时的应用,都可以直接使用这里定义的环境变量。
格式:
@@ -396,8 +396,6 @@ RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-
### ARG(构建参数)
-> 作用:
->
> `Dockerfile` 中的 `ARG` 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 `docker build` 中用 `--build-arg <参数名>=<值>` 来覆盖。
>
> 构建参数和 `ENV` 的效果一样,都是设置环境变量。所不同的是,`ARG` 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 `ARG` 保存密码之类的信息,因为 `docker history` 还是可以看到所有值的。
@@ -429,8 +427,6 @@ docker run -d -v mydata:/data xxxx
### EXPOSE(暴露端口)
-> 作用:
->
> `EXPOSE` 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 `docker run -P` 时,会自动随机映射 `EXPOSE` 的端口。
>
> 要将 `EXPOSE` 和在运行时使用 `-p <宿主端口>:<容器端口>` 区分开来。`-p`,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 `EXPOSE` 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。
@@ -439,8 +435,6 @@ docker run -d -v mydata:/data xxxx
### WORKDIR(指定工作目录)
-> 作用:
->
> 使用 `WORKDIR` 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,`WORKDIR` 会帮你建立目录。
格式:`WORKDIR <工作目录路径>`。
@@ -460,10 +454,41 @@ RUN echo "hello" > world.txt
因此如果需要改变以后各层的工作目录的位置,那么应该使用 `WORKDIR` 指令。
+### LABEL
+
+`LABEL`用于为镜像添加元数据,元数以键值对的形式指定:
+
+```
+LABEL = = = ...
+```
+
+使用`LABEL`指定元数据时,一条`LABEL`指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条`LABEL`指令指定,以免生成过多的中间镜像。
+
+如,通过`LABEL`指定一些元数据:
+
+```
+LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
+```
+
+指定后可以通过`docker inspect`查看:
+
+```
+$sudo docker inspect itbilu/test
+"Labels": {
+ "version": "1.0",
+ "description": "这是一个Web服务器",
+ "by": "IT笔录"
+},
+```
+
+*注意;*`Dockerfile`中还有个`MAINTAINER`命令,该命令用于指定镜像作者。但`MAINTAINER`并不推荐使用,更推荐使用`LABEL`来指定镜像作者。如:
+
+```
+LABEL maintainer="itbilu.com"
+```
+
### USER(指定当前用户)
-> 作用:
->
> `USER` 指令和 `WORKDIR` 相似,都是改变环境状态并影响以后的层。`WORKDIR` 是改变工作目录,`USER` 则是改变之后层的执行 `RUN`, `CMD` 以及 `ENTRYPOINT` 这类命令的身份。
>
> 当然,和 `WORKDIR` 一样,`USER` 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。
@@ -597,7 +622,7 @@ CMD [ "npm", "start" ]
把这个 `Dockerfile` 放到 Node.js 项目的根目录,构建好镜像后,就可以直接拿来启动容器运行。但是如果我们还有第二个 Node.js 项目也差不多呢?好吧,那就再把这个 `Dockerfile` 复制到第二个项目里。那如果有第三个项目呢?再复制么?文件的副本越多,版本控制就越困难,让我们继续看这样的场景维护的问题。
-如果第一个 Node.js 项目在开发过程中,发现这个 `Dockerfile` 里存在问题,比如敲错字了、或者需要安装额外的包,然后开发人员修复了这个 `Dockerfile`,再次构建,问题解决。� 第一个项目没问题了,但是第二个项目呢?虽然最初 `Dockerfile` 是复制、粘贴自第一个项目的,但是并不会因为第一个项目修复了他们的 `Dockerfile`,而第二个项目的 `Dockerfile` 就会被自动修复。
+如果第一个 Node.js 项目在开发过程中,发现这个 `Dockerfile` 里存在问题,比如敲错字了、或者需要安装额外的包,然后开发人员修复了这个 `Dockerfile`,再次构建,问题解决。第一个项目没问题了,但是第二个项目呢?虽然最初 `Dockerfile` 是复制、粘贴自第一个项目的,但是并不会因为第一个项目修复了他们的 `Dockerfile`,而第二个项目的 `Dockerfile` 就会被自动修复。
那么我们可不可以做一个基础镜像,然后各个项目使用这个基础镜像呢?这样基础镜像更新,各个项目不用同步 `Dockerfile`的变化,重新构建后就继承了基础镜像的更新?好吧,可以,让我们看看这样的结果。那么上面的这个 `Dockerfile` 就会变为:
@@ -641,9 +666,15 @@ FROM my-node
是的,只有这么一行。当在各个项目目录中,用这个只有一行的 `Dockerfile` 构建镜像时,之前基础镜像的那三行 `ONBUILD` 就会开始执行,成功的将当前项目的代码复制进镜像、并且针对本项目执行 `npm install`,生成应用镜像。
-## 引用和引申
+## 二、最佳实践
+
+
+
+有任何的问题或建议,欢迎给我留言 :laughing:
+
+## 参考资料
- [Dockerfie 官方文档](https://docs.docker.com/engine/reference/builder/)
-- [Dockerfile 最佳实践文档](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
+- [Best practices for writing Dockerfiles](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
- [Docker 官方镜像 Dockerfile](https://github.com/docker-library/docs)
- [Dockerfile 指令详解](https://yeasy.gitbooks.io/docker_practice/content/image/dockerfile/)
diff --git a/docs/docker/docker-quickstart.md b/docs/docker/docker-quickstart.md
new file mode 100644
index 00000000..4c5434fb
--- /dev/null
+++ b/docs/docker/docker-quickstart.md
@@ -0,0 +1,357 @@
+# Docker 快速入门
+
+
+
+- [一、Docker 的简介](#一docker-的简介)
+- [二、Docker 的运维](#二docker-的运维)
+- [三、hello world 实例](#三hello-world-实例)
+- [四、制作 Docker 容器](#四制作-docker-容器)
+- [参考资料](#参考资料)
+
+
+
+## 一、Docker 的简介
+
+### 什么是 Docker
+
+> **Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。**
+
+它是目前最流行的 Linux 容器解决方案。
+
+Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。
+
+总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
+
+### 为什么需要 Docker
+
+- **更高效的利用系统资源** - 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,`Docker` 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
+- **更快速的启动时间** - 传统的虚拟机技术启动应用服务往往需要数分钟,而 `Docker` 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。
+- **一致的运行环境** - 开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 `Docker` 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 _「这段代码在我机器上没问题啊」_ 这类问题。
+- **持续交付和部署** - 对开发和运维([DevOps](https://zh.wikipedia.org/wiki/DevOps))人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。使用 `Docker` 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 [Dockerfile](https://yeasy.gitbooks.io/docker_practice/image/dockerfile) 来进行镜像构建,并结合 [持续集成(Continuous Integration)](https://en.wikipedia.org/wiki/Continuous_integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 [持续部署(Continuous Delivery/Deployment)](https://en.wikipedia.org/wiki/Continuous_delivery) 系统进行自动部署。而且使用 [`Dockerfile`](https://yeasy.gitbooks.io/docker_practice/image/build.html) 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。
+- **更轻松的迁移** - 由于 `Docker` 确保了执行环境的一致性,使得应用的迁移更加容易。`Docker` 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
+- **更轻松的维护和扩展** - `Docker` 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,`Docker` 团队同各个开源项目团队一起维护了一大批高质量的 [官方镜像](https://hub.docker.com/search/?type=image&image_filter=official),既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。
+
+
+
+### Docker 的主要用途
+
+Docker 提供了被称为容器的松散隔离环境,在环境中可以打包和运行应用程序。隔离和安全性允许您在给定主机上同时运行多个容器。容器是轻量级的,因为它们不需要管理程序的额外负载,而是直接在主机的内核中运行。这意味着您可以在给定的硬件组合上运行更多容器,而不是使用虚拟机。你甚至可以在实际上是虚拟机的主机中运行 Docker 容器!
+
+Docker 的主要用途,目前有三大类。
+
+- **提供一次性的环境。**比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
+- **提供弹性的云服务。**因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
+- **组建微服务架构。**通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
+
+### Docker 的核心概念
+
+#### 镜像
+
+Docker 把应用程序及其依赖,打包在镜像(Image)文件里面。
+
+我们都知道,操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。
+
+Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
+
+**分层存储**
+
+因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
+
+镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
+
+分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
+
+#### 容器
+
+镜像(`Image`)和容器(`Container`)的关系,就像是面向对象程序设计中的 `类` 和 `实例` 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
+
+容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 [命名空间](https://en.wikipedia.org/wiki/Linux_namespaces)。因此容器可以拥有自己的 `root` 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。
+
+前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为**容器存储层**。
+
+容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。
+
+按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 [数据卷(Volume)](https://yeasy.gitbooks.io/docker_practice/content/data_management/volume.html)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
+
+数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。
+
+#### 仓库
+
+镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,[Docker Registry](https://yeasy.gitbooks.io/docker_practice/content/repository/registry.html) 就是这样的服务。
+
+一个 **Docker Registry** 中可以包含多个**仓库**(`Repository`);每个仓库可以包含多个**标签**(`Tag`);每个标签对应一个镜像。
+
+通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 `<仓库名>:<标签>` 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 `latest` 作为默认标签。
+
+以 [Ubuntu 镜像](https://store.docker.com/images/ubuntu) 为例,`ubuntu` 是仓库的名字,其内包含有不同的版本标签,如,`16.04`, `18.04`。我们可以通过 `ubuntu:14.04`,或者 `ubuntu:18.04` 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 `ubuntu`,那将视为 `ubuntu:latest`。
+
+仓库名经常以 _两段式路径_ 形式出现,比如 `jwilder/nginx-proxy`,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。
+
+## 二、Docker 的运维
+
+不同操作系统环境下安装 Docker 的方式有所不同,详情可以参:
+
+- [Docker 官方安装指南](https://docs.docker.com/install/)
+- [安装 Docker(中文)](https://docker_practice.gitee.io/install/)
+
+国内访问 Docker 比较慢,如果需要提速,可以参考 [镜像加速器](https://docker_practice.gitee.io/install/mirror.html)
+
+安装完成后,运行下面的命令,验证是否安装成功。
+
+- `docker version`
+- `docker info`
+
+Docker 需要用户具有 sudo 权限,为了避免每次命令都输入`sudo`,可以把用户加入 Docker 用户组([官方文档](https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user))。
+
+```bash
+$ sudo usermod -aG docker $USER
+```
+
+Docker 是服务器----客户端架构。命令行运行`docker`命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动([官方文档](https://docs.docker.com/config/daemon/systemd/))。
+
+```bash
+# service 命令的用法
+$ sudo service docker start
+
+# systemctl 命令的用法
+$ sudo systemctl start docker
+```
+
+## 三、Hello World 实例
+
+下面,我们通过最简单的 image 文件"[hello world"](https://hub.docker.com/r/library/hello-world/),感受一下 Docker。
+
+需要说明的是,国内连接 Docker 的官方仓库很慢,还会断线,需要将默认仓库改成国内的镜像网站,具体的修改方法在[下一篇文章](http://www.ruanyifeng.com/blog/2018/02/docker-wordpress-tutorial.html)的第一节。有需要的朋友,可以先看一下。
+
+首先,运行下面的命令,将 image 文件从仓库抓取到本地。
+
+> ```bash
+> $ docker image pull library/hello-world
+> ```
+
+上面代码中,`docker image pull`是抓取 image 文件的命令。`library/hello-world`是 image 文件在仓库里面的位置,其中`library`是 image 文件所在的组,`hello-world`是 image 文件的名字。
+
+由于 Docker 官方提供的 image 文件,都放在[`library`](https://hub.docker.com/r/library/)组里面,所以它的是默认组,可以省略。因此,上面的命令可以写成下面这样。
+
+> ```bash
+> $ docker image pull hello-world
+> ```
+
+抓取成功以后,就可以在本机看到这个 image 文件了。
+
+> ```bash
+> $ docker image ls
+> ```
+
+现在,运行这个 image 文件。
+
+> ```bash
+> $ docker container run hello-world
+> ```
+
+`docker container run`命令会从 image 文件,生成一个正在运行的容器实例。
+
+注意,`docker container run`命令具有自动抓取 image 文件的功能。如果发现本地没有指定的 image 文件,就会从仓库自动抓取。因此,前面的`docker image pull`命令并不是必需的步骤。
+
+如果运行成功,你会在屏幕上读到下面的输出。
+
+> ```bash
+> $ docker container run hello-world
+>
+> Hello from Docker!
+> This message shows that your installation appears to be working correctly.
+>
+> ... ...
+> ```
+
+输出这段提示以后,`hello world`就会停止运行,容器自动终止。
+
+有些容器不会自动终止,因为提供的是服务。比如,安装运行 Ubuntu 的 image,就可以在命令行体验 Ubuntu 系统。
+
+> ```bash
+> $ docker container run -it ubuntu bash
+> ```
+
+对于那些不会自动终止的容器,必须使用[`docker container kill`](https://docs.docker.com/engine/reference/commandline/container_kill/) 命令手动终止。
+
+> ```bash
+> $ docker container kill [containID]
+> ```
+
+## 四、制作 Docker 容器
+
+下面我以 [koa-demos](http://www.ruanyifeng.com/blog/2017/08/koa.html) 项目为例,介绍怎么写 Dockerfile 文件,实现让用户在 Docker 容器里面运行 Koa 框架。
+
+作为准备工作,请先[下载源码](https://github.com/ruanyf/koa-demos/archive/master.zip)。
+
+> ```bash
+> $ git clone https://github.com/ruanyf/koa-demos.git
+> $ cd koa-demos
+> ```
+
+### 编写 Dockerfile 文件
+
+首先,在项目的根目录下,新建一个文本文件`.dockerignore`,写入下面的[内容](https://github.com/ruanyf/koa-demos/blob/master/.dockerignore)。
+
+> ```bash
+> .git
+> node_modules
+> npm-debug.log
+> ```
+
+上面代码表示,这三个路径要排除,不要打包进入 image 文件。如果你没有路径要排除,这个文件可以不新建。
+
+然后,在项目的根目录下,新建一个文本文件 Dockerfile,写入下面的[内容](https://github.com/ruanyf/koa-demos/blob/master/Dockerfile)。
+
+> ```bash
+> FROM node:8.4
+> COPY . /app
+> WORKDIR /app
+> RUN npm install --registry=https://registry.npm.taobao.org
+> EXPOSE 3000
+> ```
+
+上面代码一共五行,含义如下。
+
+> - `FROM node:8.4`:该 image 文件继承官方的 node image,冒号表示标签,这里标签是`8.4`,即 8.4 版本的 node。
+> - `COPY . /app`:将当前目录下的所有文件(除了`.dockerignore`排除的路径),都拷贝进入 image 文件的`/app`目录。
+> - `WORKDIR /app`:指定接下来的工作路径为`/app`。
+> - `RUN npm install`:在`/app`目录下,运行`npm install`命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。
+> - `EXPOSE 3000`:将容器 3000 端口暴露出来, 允许外部连接这个端口。
+
+### 创建 image 文件
+
+有了 Dockerfile 文件以后,就可以使用`docker image build`命令创建 image 文件了。
+
+> ```bash
+> $ docker image build -t koa-demo .
+> # 或者
+> $ docker image build -t koa-demo:0.0.1 .
+> ```
+
+上面代码中,`-t`参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是`latest`。最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。
+
+如果运行成功,就可以看到新生成的 image 文件`koa-demo`了。
+
+> ```bash
+> $ docker image ls
+> ```
+
+### 生成容器
+
+`docker container run`命令会从 image 文件生成容器。
+
+> ```bash
+> $ docker container run -p 8000:3000 -it koa-demo /bin/bash
+> # 或者
+> $ docker container run -p 8000:3000 -it koa-demo:0.0.1 /bin/bash
+> ```
+
+上面命令的各个参数含义如下:
+
+> - `-p`参数:容器的 3000 端口映射到本机的 8000 端口。
+> - `-it`参数:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。
+> - `koa-demo:0.0.1`:image 文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)。
+> - `/bin/bash`:容器启动以后,内部第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell。
+
+如果一切正常,运行上面的命令以后,就会返回一个命令行提示符。
+
+> ```bash
+> root@66d80f4aaf1e:/app#
+> ```
+
+这表示你已经在容器里面了,返回的提示符就是容器内部的 Shell 提示符。执行下面的命令。
+
+> ```bash
+> root@66d80f4aaf1e:/app# node demos/01.js
+> ```
+
+这时,Koa 框架已经运行起来了。打开本机的浏览器,访问 http://127.0.0.1:8000,网页显示"Not Found",这是因为这个 [demo](https://github.com/ruanyf/koa-demos/blob/master/demos/01.js) 没有写路由。
+
+这个例子中,Node 进程运行在 Docker 容器的虚拟环境里面,进程接触到的文件系统和网络接口都是虚拟的,与本机的文件系统和网络接口是隔离的,因此需要定义容器与物理机的端口映射(map)。
+
+现在,在容器的命令行,按下 Ctrl + c 停止 Node 进程,然后按下 Ctrl + d (或者输入 exit)退出容器。此外,也可以用`docker container kill`终止容器运行。
+
+> ```bash
+> # 在本机的另一个终端窗口,查出容器的 ID
+> $ docker container ls
+>
+> # 停止指定的容器运行
+> $ docker container kill [containerID]
+> ```
+
+容器停止运行之后,并不会消失,用下面的命令删除容器文件。
+
+> ```bash
+> # 查出容器的 ID
+> $ docker container ls --all
+>
+> # 删除指定的容器文件
+> $ docker container rm [containerID]
+> ```
+
+也可以使用`docker container run`命令的`--rm`参数,在容器终止运行后自动删除容器文件。
+
+> ```bash
+> $ docker container run --rm -p 8000:3000 -it koa-demo /bin/bash
+> ```
+
+### CMD 命令
+
+上一节的例子里面,容器启动以后,需要手动输入命令`node demos/01.js`。我们可以把这个命令写在 Dockerfile 里面,这样容器启动以后,这个命令就已经执行了,不用再手动输入了。
+
+> ```bash
+> FROM node:8.4
+> COPY . /app
+> WORKDIR /app
+> RUN npm install --registry=https://registry.npm.taobao.org
+> EXPOSE 3000
+> CMD node demos/01.js
+> ```
+
+上面的 Dockerfile 里面,多了最后一行`CMD node demos/01.js`,它表示容器启动后自动执行`node demos/01.js`。
+
+你可能会问,`RUN`命令与`CMD`命令的区别在哪里?简单说,`RUN`命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;`CMD`命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个`RUN`命令,但是只能有一个`CMD`命令。
+
+注意,指定了`CMD`命令以后,`docker container run`命令就不能附加命令了(比如前面的`/bin/bash`),否则它会覆盖`CMD`命令。现在,启动容器可以使用下面的命令。
+
+> ```bash
+> $ docker container run --rm -p 8000:3000 -it koa-demo:0.0.1
+> ```
+
+### 发布 image 文件
+
+容器运行成功后,就确认了 image 文件的有效性。这时,我们就可以考虑把 image 文件分享到网上,让其他人使用。
+
+首先,去 [hub.docker.com](https://hub.docker.com/) 或 [cloud.docker.com](https://cloud.docker.com/) 注册一个账户。然后,用下面的命令登录。
+
+> ```bash
+> $ docker login
+> ```
+
+接着,为本地的 image 标注用户名和版本。
+
+> ```bash
+> $ docker image tag [imageName] [username]/[repository]:[tag]
+> # 实例
+> $ docker image tag koa-demos:0.0.1 ruanyf/koa-demos:0.0.1
+> ```
+
+也可以不标注用户名,重新构建一下 image 文件。
+
+> ```bash
+> $ docker image build -t [username]/[repository]:[tag] .
+> ```
+
+最后,发布 image 文件。
+
+> ```bash
+> $ docker image push [username]/[repository]:[tag]
+> ```
+
+发布成功以后,登录 hub.docker.com,就可以看到已经发布的 image 文件。
+
+## 参考资料
+
+- [Docker 入门教程](https://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html)
+- [Docker — 从入门到实践](https://github.com/yeasy/docker_practice)
diff --git a/docs/docker/docker.md b/docs/docker/docker.md
deleted file mode 100644
index 50d7e2ae..00000000
--- a/docs/docker/docker.md
+++ /dev/null
@@ -1,154 +0,0 @@
-# Docker 应用指南
-
-## 简介
-
-### Docker 是什么
-
-> **Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。**
-
-Docker 是目前最流行的 Linux 容器解决方案。
-
-Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。
-
-总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
-
-### Docker 的用途
-
-Docker 的主要用途,目前有三大类。
-
-- **提供一次性的环境** - 比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
-- **提供弹性的云服务** - 因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
-- **组建微服务架构** - 通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
-
-### 虚拟机和 Docker
-
-虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 系统里面运行 Linux 系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。
-
-**资源占用多** - 虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有 1MB,虚拟机依然需要几百 MB 的内存才能运行。
-
-**冗余步骤多** - 虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。
-
-**启动慢** - 启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。
-
-
-
-### Docker 平台
-
-Docker 提供了被称为容器的松散隔离环境,在环境中可以打包和运行应用程序。隔离和安全性允许您在给定主机上同时运行多个容器。容器是轻量级的,因为它们不需要管理程序的额外负载,而是直接在主机的内核中运行。这意味着您可以在给定的硬件组合上运行更多容器,而不是使用虚拟机。你甚至可以在实际上是虚拟机的主机中运行 Docker 容器!
-
-Docker 提供工具和平台来管理容器的生命周期:
-
-- 使用容器开发您的应用程序及其支持组件。
-- 容器成为分发和测试你的应用程序的单元。
-- 准备好后,将您的应用程序部署到生产环境中,作为容器或协调服务。无论您的生产环境是本地数据中心,云提供商还是两者的混合,这都是一样的。
-
-## 核心概念
-
-### 引擎
-
-Docker 引擎是一个 C/S 架构的应用,它有这些主要的组件:
-
-服务器是一个长期运行的程序,被称为守护进程。
-
-REST API 指定程序可用于与守护进程进行通信并指示其执行操作的接口。
-
-命令行客户端。
-
-
-
-CLI 使用 Docker REST API 通过脚本或直接 CLI 命令来控制 Docker 守护进程或与其进行交互。许多其他 Docker 应用程序使用底层的 API 和 CLI。
-
-守护进程创建并管理 Docker 对象,如镜像,容器,网络和卷。
-
-### 镜像
-
-我们都知道,操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。
-
-Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
-
-**分层存储**
-
-因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
-
-镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
-
-分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
-
-### 容器
-
-镜像(`Image`)和容器(`Container`)的关系,就像是面向对象程序设计中的 `类` 和 `实例` 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
-
-容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 [命名空间](https://en.wikipedia.org/wiki/Linux_namespaces)。因此容器可以拥有自己的 `root` 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。
-
-前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为**容器存储层**。
-
-容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。
-
-按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 [数据卷(Volume)](https://yeasy.gitbooks.io/docker_practice/content/data_management/volume.html)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
-
-数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。
-
-### 仓库
-
-镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,[Docker Registry](https://yeasy.gitbooks.io/docker_practice/content/repository/registry.html) 就是这样的服务。
-
-一个 **Docker Registry** 中可以包含多个**仓库**(`Repository`);每个仓库可以包含多个**标签**(`Tag`);每个标签对应一个镜像。
-
-通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 `<仓库名>:<标签>` 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 `latest` 作为默认标签。
-
-以 [Ubuntu 镜像](https://store.docker.com/images/ubuntu) 为例,`ubuntu` 是仓库的名字,其内包含有不同的版本标签,如,`16.04`, `18.04`。我们可以通过 `ubuntu:14.04`,或者 `ubuntu:18.04` 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 `ubuntu`,那将视为 `ubuntu:latest`。
-
-仓库名经常以 _两段式路径_ 形式出现,比如 `jwilder/nginx-proxy`,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。
-
-## 安装配置
-
-不同操作系统环境下安装 Docker 的方式有所不同,详情可以参:
-
-- [Docker 官方安装指南](https://docs.docker.com/install/)
-- [安装 Docker(中文)](https://docker_practice.gitee.io/install/)
-
-国内访问 Docker 比较慢,如果需要提速,可以参考 [镜像加速器](https://docker_practice.gitee.io/install/mirror.html)
-
-安装完成后,运行下面的命令,验证是否安装成功。
-
-- `docker version`
-- `docker info`
-
-Docker 需要用户具有 sudo 权限,为了避免每次命令都输入`sudo`,可以把用户加入 Docker 用户组([官方文档](https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user))。
-
-```bash
-$ sudo usermod -aG docker $USER
-```
-
-Docker 是服务器----客户端架构。命令行运行`docker`命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动([官方文档](https://docs.docker.com/config/daemon/systemd/))。
-
-```bash
-# service 命令的用法
-$ sudo service docker start
-
-# systemctl 命令的用法
-$ sudo systemctl start docker
-```
-
-## 参考资料
-
-- Docker 官方资源
- - [Docker 官网](http://www.docker.com)
- - [Docker Github](https://github.com/moby/moby)
- - [Docker 官方文档](https://docs.docker.com/)
- - [Docker Hub](https://hub.docker.com/)
- - [Docker 开源](https://www.docker.com/community/open-source)
-- 资源整理
- - [Awesome Docker](https://github.com/veggiemonk/awesome-docker)
-- Docker 中文资源
- - [Docker 中文网站](https://www.docker-cn.com/)
- - [Docker 安装手册](https://docs.docker-cn.com/engine/installation/)
- - [Docker — 从入门到实践](https://docker_practice.gitee.io/)
-- Docker 国内镜像
- - [时速云镜像仓库](https://hub.tenxcloud.com/)
- - [网易云镜像服务](https://c.163.com/hub#/m/library/)
- - [DaoCloud 镜像市场](https://hub.daocloud.io/)
- - [阿里云镜像库](https://cr.console.aliyun.com/)
-- 文章
- - [Docker 入门教程](http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html)
- - [Docker Cheat Sheet](https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn)
diff --git a/docs/docker/kubernetes.md b/docs/docker/kubernetes.md
new file mode 100644
index 00000000..82daee1c
--- /dev/null
+++ b/docs/docker/kubernetes.md
@@ -0,0 +1,180 @@
+# Kubernetes 应用指南
+
+> Kubernetes 是谷歌开源的容器集群管理系统 是用于自动部署,扩展和管理 Docker 应用程序的开源系统,简称 K8S。
+>
+> 关键词: `docker`
+
+
+
+- [一、K8S 简介](#一k8s-简介)
+- [二、K8S 命令](#二k8s-命令)
+- [参考资料](#参考资料)
+
+
+
+## 一、K8S 简介
+
+K8S 主控组件(Master) 包含三个进程,都运行在集群中的某个节上,通常这个节点被称为 master 节点。这些进程包括:`kube-apiserver`、`kube-controller-manager` 和 `kube-scheduler`。
+
+集群中的每个非 master 节点都运行两个进程:
+
+- kubelet,和 master 节点进行通信。
+- kube-proxy,一种网络代理,将 Kubernetes 的网络服务代理到每个节点上。
+
+### K8S 功能
+
+- 基于容器的应用部署、维护和滚动升级
+- 负载均衡和服务发现
+- 跨机器和跨地区的集群调度
+- 自动伸缩
+- 无状态服务和有状态服务
+- 广泛的 Volume 支持
+- 插件机制保证扩展性
+
+### K8S 核心组件
+
+Kubernetes 主要由以下几个核心组件组成:
+
+- etcd 保存了整个集群的状态;
+- apiserver 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;
+- controller manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;
+- scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;
+- kubelet 负责维护容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;
+- Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI);
+- kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡
+
+
+
+### K8S 核心概念
+
+K8S 包含若干抽象用来表示系统状态,包括:已部署的容器化应用和负载、与它们相关的网络和磁盘资源以及有关集群正在运行的其他操作的信息。
+
+
+
+- `Pod` - K8S 使用 Pod 来管理容器,每个 Pod 可以包含一个或多个紧密关联的容器。Pod 是一组紧密关联的容器集合,它们共享 PID、IPC、Network 和 UTS namespace,是 K8S 调度的基本单位。Pod 内的多个容器共享网络和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。
+- `Node` - Node 是 Pod 真正运行的主机,可以是物理机,也可以是虚拟机。为了管理 Pod,每个 Node 节点上至少要运行 container runtime(比如 docker 或者 rkt)、`kubelet` 和 `kube-proxy` 服务。
+- `Namespace` - Namespace 是对一组资源和对象的抽象集合,比如可以用来将系统内部的对象划分为不同的项目组或用户组。常见的 pods, services, replication controllers 和 deployments 等都是属于某一个 namespace 的(默认是 default),而 node, persistentVolumes 等则不属于任何 namespace。
+- `Service` - Service 是应用服务的抽象,通过 labels 为应用提供负载均衡和服务发现。匹配 labels 的 Pod IP 和端口列表组成 endpoints,由 kube-proxy 负责将服务 IP 负载均衡到这些 endpoints 上。每个 Service 都会自动分配一个 cluster IP(仅在集群内部可访问的虚拟地址)和 DNS 名,其他容器可以通过该地址或 DNS 来访问服务,而不需要了解后端容器的运行。
+- `Label` - Label 是识别 K8S 对象的标签,以 key/value 的方式附加到对象上(key 最长不能超过 63 字节,value 可以为空,也可以是不超过 253 字节的字符串)。Label 不提供唯一性,并且实际上经常是很多对象(如 Pods)都使用相同的 label 来标志具体的应用。Label 定义好后其他对象可以使用 Label Selector 来选择一组相同 label 的对象(比如 ReplicaSet 和 Service 用 label 来选择一组 Pod)。Label Selector 支持以下几种方式:
+ - 等式,如 `app=nginx` 和 `env!=production`
+ - 集合,如 `env in (production, qa)`
+ - 多个 label(它们之间是 AND 关系),如 `app=nginx,env=test`
+- `Annotations` - Annotations 是 key/value 形式附加于对象的注解。不同于 Labels 用于标志和选择对象,Annotations 则是用来记录一些附加信息,用来辅助应用部署、安全策略以及调度策略等。比如 deployment 使用 annotations 来记录 rolling update 的状态。
+
+## 二、K8S 命令
+
+### 客户端配置
+
+```bash
+# Setup autocomplete in bash; bash-completion package should be installed first
+source <(kubectl completion bash)
+
+# View Kubernetes config
+kubectl config view
+
+# View specific config items by json path
+kubectl config view -o jsonpath='{.users[?(@.name == "k8s")].user.password}'
+
+# Set credentials for foo.kuberntes.com
+kubectl config set-credentials kubeuser/foo.kubernetes.com --username=kubeuser --password=kubepassword
+```
+
+### 查找资源
+
+```bash
+# List all services in the namespace
+kubectl get services
+
+# List all pods in all namespaces in wide format
+kubectl get pods -o wide --all-namespaces
+
+# List all pods in json (or yaml) format
+kubectl get pods -o json
+
+# Describe resource details (node, pod, svc)
+kubectl describe nodes my-node
+
+# List services sorted by name
+kubectl get services --sort-by=.metadata.name
+
+# List pods sorted by restart count
+kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'
+
+# Rolling update pods for frontend-v1
+kubectl rolling-update frontend-v1 -f frontend-v2.json
+
+# Scale a replicaset named 'foo' to 3
+kubectl scale --replicas=3 rs/foo
+
+# Scale a resource specified in "foo.yaml" to 3
+kubectl scale --replicas=3 -f foo.yaml
+
+# Execute a command in every pod / replica
+for i in 0 1; do kubectl exec foo-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done
+```
+
+### 资源管理
+
+```bash
+# Get documentation for pod or service
+kubectl explain pods,svc
+
+# Create resource(s) like pods, services or daemonsets
+kubectl create -f ./my-manifest.yaml
+
+# Apply a configuration to a resource
+kubectl apply -f ./my-manifest.yaml
+
+# Start a single instance of Nginx
+kubectl run nginx --image=nginx
+
+# Create a secret with several keys
+cat <..." to unstage)
-#
-# modified: lib/test.rb
-#
-~
-~
-".git/COMMIT_EDITMSG" 14L, 297C
-```
-
-如果你的团队对提交信息有格式要求,可以在系统上创建一个文件,并配置 Git 把它作为默认的模板,这样可以更加容易地使提交信息遵循格式。
-
-### `core.pager`
-
-该配置项指定 Git 运行诸如 `log` 和 `diff` 等命令所使用的分页器。 你可以把它设置成用 `more` 或者任何你喜欢的分页器(默认用的是 `less`),当然也可以设置成空字符串,关闭该选项:
-
-```
-$ git config --global core.pager ''
-```
-
-这样不管命令的输出量多少,Git 都会在一页显示所有内容。
-
-### `user.signingkey`
-
-如果你要创建经签署的含附注的标签(正如 [签署工作](https://git-scm.com/book/zh/v2/ch00/r_signing) 所述),那么把你的 GPG 签署密钥设置为配置项会更好。 如下设置你的密钥 ID:
-
-```
-$ git config --global user.signingkey
-```
-
-现在,你每次运行 `git tag` 命令时,即可直接签署标签,而无需定义密钥:
-
-```
-$ git tag -s
-```
-
-### `core.excludesfile`
-
-正如 [忽略文件](https://git-scm.com/book/zh/v2/ch00/r_ignoring) 所述,你可以在你的项目的 `.gitignore` 文件里面规定无需纳入 Git 管理的文件的模板,这样它们既不会出现在未跟踪列表,也不会在你运行 `git add` 后被暂存。
-
-不过有些时候,你想要在你所有的版本库中忽略掉某一类文件。 如果你的操作系统是 OS X,很可能就是指`.DS_Store`。 如果你把 Emacs 或 Vim 作为首选的编辑器,你肯定知道以 `\~` 结尾的临时文件。
-
-这个配置允许你设置类似于全局生效的 `.gitignore` 文件。 如果你按照下面的内容创建一个`\~/.gitignore_global` 文件:
-
-```
-*~
-.DS_Store
-```
-
-……然后运行 `git config --global core.excludesfile \~/.gitignore_global`,Git 将把那些文件永远地拒之门外。
-
-### `help.autocorrect`
-
-假如你打错了一条命令,会显示:
-
-```
-$ git chekcout master
-git:'chekcout' 不是一个 git 命令。参见 'git --help'。
-
-您指的是这个么?
- checkout
-```
-
-Git 会尝试猜测你的意图,但是它不会越俎代庖。 如果你把 `help.autocorrect` 设置成 1,那么只要有一个命令被模糊匹配到了,Git 会自动运行该命令。
-
-```
-$ git chekcout master
-警告:您运行一个不存在的 Git 命令 'chekcout'。继续执行假定您要要运行的
-是 'checkout'
-在 0.1 秒钟后自动运行...
-```
-
-注意提示信息中的“0.1 秒”。`help.autocorrect` 接受一个代表十分之一秒的整数。 所以如果你把它设置为 50, Git 将在自动执行命令前给你 5 秒的时间改变主意。
-
-## 格式化与多余的空白字符
-
-格式化与多余的空白字符是许多开发人员在协作时,特别是在跨平台情况下,不时会遇到的令人头疼的琐碎的问题。 由于编辑器的不同或者文件行尾的换行符在 Windows 下被替换了,一些细微的空格变化会不经意地混入提交的补丁或其它协作成果中。 不用怕,Git 提供了一些配置项来帮助你解决这些问题。
-
-### `core.autocrlf`
-
-假如你正在 Windows 上写程序,而你的同伴用的是其他系统(或相反),你可能会遇到 CRLF 问题。 这是因为 Windows 使用回车(CR)和换行(LF)两个字符来结束一行,而 Mac 和 Linux 只使用换行(LF)一个字符。 虽然这是小问题,但它会极大地扰乱跨平台协作。许多 Windows 上的编辑器会悄悄把行尾的换行字符转换成回车和换行,或在用户按下 Enter 键时,插入回车和换行两个字符。
-
-Git 可以在你提交时自动地把回车和换行转换成换行,而在检出代码时把换行转换成回车和换行。 你可以用 `core.autocrlf` 来打开此项功能。 如果是在 Windows 系统上,把它设置成 `true`,这样在检出代码时,换行会被转换成回车和换行:
-
-```
-$ git config --global core.autocrlf true
-```
-
-如果使用以换行作为行结束符的 Linux 或 Mac,你不需要 Git 在检出文件时进行自动的转换;然而当一个以回车加换行作为行结束符的文件不小心被引入时,你肯定想让 Git 修正。 你可以把 `core.autocrlf` 设置成 input 来告诉 Git 在提交时把回车和换行转换成换行,检出时不转换:
-
-```
-$ git config --global core.autocrlf input
-```
-
-这样在 Windows 上的检出文件中会保留回车和换行,而在 Mac 和 Linux 上,以及版本库中会保留换行。
-
-如果你是 Windows 程序员,且正在开发仅运行在 Windows 上的项目,可以设置 `false` 取消此功能,把回车保留在版本库中:
-
-```
-$ git config --global core.autocrlf false
-```
-
-### `core.whitespace`
-
-Git 预先设置了一些选项来探测和修正多余空白字符问题。 它提供了六种处理多余空白字符的主要选项 —— 其中三个默认开启,另外三个默认关闭,不过你可以自由地设置它们。
-
-默认被打开的三个选项是:`blank-at-eol`,查找行尾的空格;`blank-at-eof`,盯住文件底部的空行;`space-before-tab`,警惕行头 tab 前面的空格。
-
-默认被关闭的三个选项是:`indent-with-non-tab`,揪出以空格而非 tab 开头的行(你可以用 `tabwidth`选项控制它);`tab-in-indent`,监视在行头表示缩进的 tab;`cr-at-eol`,告诉 Git 忽略行尾的回车。
-
-通过设置 `core.whitespace`,你可以让 Git 按照你的意图来打开或关闭以逗号分割的选项。 要想关闭某个选项,你可以在输入设置选项时不指定它或在它前面加个 `-`。 例如,如果你想要打开除 `cr-at-eol` 之外的所有选项:
-
-```
-$ git config --global core.whitespace \
- trailing-space,space-before-tab,indent-with-non-tab
-```
-
-当你运行 `git diff` 命令并尝试给输出着色时,Git 将探测到这些问题,因此你在提交前就能修复它们。 用`git apply` 打补丁时你也会从中受益。 如果正准备应用的补丁存有特定的空白问题,你可以让 Git 在应用补丁时发出警告:
-
-```
-$ git apply --whitespace=warn
-```
-
-或者让 Git 在打上补丁前自动修正此问题:
-
-```
-$ git apply --whitespace=fix
-```
-
-这些选项也能运用于 `git rebase`。 如果提交了有空白问题的文件,但还没推送到上游,你可以运行 `git rebase --whitespace=fix` 来让 Git 在重写补丁时自动修正它们。
-
-## 服务器端配置
-
-Git 服务器端的配置项相对来说并不多,但仍有一些饶有生趣的选项值得你一看。
-
-### `receive.fsckObjects`
-
-Git 能够确认每个对象的有效性以及 SHA-1 检验和是否保持一致。 但 Git 不会在每次推送时都这么做。这个操作很耗时间,很有可能会拖慢提交的过程,特别是当库或推送的文件很大的情况下。 如果想在每次推送时都要求 Git 检查一致性,设置 `receive.fsckObjects` 为 true 来强迫它这么做:
-
-```
-$ git config --system receive.fsckObjects true
-```
-
-现在 Git 会在每次推送生效前检查库的完整性,确保没有被有问题的客户端引入破坏性数据。
-
-### `receive.denyNonFastForwards`
-
-如果你变基已经被推送的提交,继而再推送,又或者推送一个提交到远程分支,而这个远程分支当前指向的提交不在该提交的历史中,这样的推送会被拒绝。 这通常是个很好的策略,但有时在变基的过程中,你确信自己需要更新远程分支,可以在 push 命令后加 `-f` 标志来强制更新(force-update)。
-
-要禁用这样的强制更新推送(force-pushes),可以设置 `receive.denyNonFastForwards`:
-
-```
-$ git config --system receive.denyNonFastForwards true
-```
-
-稍后我们会提到,用服务器端的接收钩子也能达到同样的目的。 那种方法可以做到更细致的控制,例如禁止某一类用户做非快进(non-fast-forwards)推送。
-
-### `receive.denyDeletes`
-
-有一些方法可以绕过 `denyNonFastForwards` 策略。其中一种是先删除某个分支,再连同新的引用一起推送回该分支。 把 `receive.denyDeletes` 设置为 true 可以把这个漏洞补上:
-
-```
-$ git config --system receive.denyDeletes true
-```
-
-这样会禁止通过推送删除分支和标签 — 没有用户可以这么做。 要删除远程分支,必须从服务器手动删除引用文件。 通过用户访问控制列表(ACL)也能够在用户级的粒度上实现同样的功能,你将在 [使用强制策略的一个例子](https://git-scm.com/book/zh/v2/ch00/r_an_example_git_enforced_policy) 一节学到具体的做法。
diff --git a/docs/git/git-faq.md b/docs/git/git-faq.md
deleted file mode 100644
index 4297aed3..00000000
--- a/docs/git/git-faq.md
+++ /dev/null
@@ -1,858 +0,0 @@
-# Git 常见问题
-
-## 编辑提交(editting commits)
-
-### 我刚才提交了什么
-
-如果你用 `git commit -a` 提交了一次变化(changes),而你又不确定到底这次提交了哪些内容。 你就可以用下面的命令显示当前`HEAD`上的最近一次的提交(commit):
-
-```bash
-(master)$ git show
-```
-
-或者
-
-```bash
-$ git log -n1 -p
-```
-
-### 我的提交信息(commit message)写错了
-
-如果你的提交信息(commit message)写错了且这次提交(commit)还没有推(push), 你可以通过下面的方法来修改提交信息(commit message):
-
-```bash
-$ git commit --amend
-```
-
-这会打开你的默认编辑器, 在这里你可以编辑信息. 另一方面, 你也可以用一条命令一次完成:
-
-```bash
-$ git commit --amend -m 'xxxxxxx'
-```
-
-如果你已经推(push)了这次提交(commit), 你可以修改这次提交(commit)然后强推(force push), 但是不推荐这么做。
-
-### 我提交(commit)里的用户名和邮箱不对
-
-如果这只是单个提交(commit),修改它:
-
-```bash
-$ git commit --amend --author "New Authorname "
-```
-
-如果你需要修改所有历史, 参考 'git filter-branch'的指南页.
-
-### 我想从一个提交(commit)里移除一个文件
-
-通过下面的方法,从一个提交(commit)里移除一个文件:
-
-```bash
-$ git checkout HEAD^ myfile
-$ git add -A
-$ git commit --amend
-```
-
-这将非常有用,当你有一个开放的补丁(open patch),你往上面提交了一个不必要的文件,你需要强推(force push)去更新这个远程补丁。
-
-### 我想删除我的的最后一次提交(commit)
-
-如果你需要删除推了的提交(pushed commits),你可以使用下面的方法。可是,这会不可逆的改变你的历史,也会搞乱那些已经从该仓库拉取(pulled)了的人的历史。简而言之,如果你不是很确定,千万不要这么做。
-
-```bash
-$ git reset HEAD^ --hard
-$ git push -f [remote] [branch]
-```
-
-如果你还没有推到远程, 把 Git 重置(reset)到你最后一次提交前的状态就可以了(同时保存暂存的变化):
-
-```
-(my-branch*)$ git reset --soft HEAD@{1}
-
-```
-
-这只能在没有推送之前有用. 如果你已经推了, 唯一安全能做的是 `git revert SHAofBadCommit`, 那会创建一个新的提交(commit)用于撤消前一个提交的所有变化(changes); 或者, 如果你推的这个分支是 rebase-safe 的 (例如: 其它开发者不会从这个分支拉), 只需要使用 `git push -f`; 更多, 请参考 [the above section](#deleteremove-last-pushed-commit)。
-
-### 删除任意提交(commit)
-
-同样的警告:不到万不得已的时候不要这么做.
-
-```bash
-$ git rebase --onto SHA1_OF_BAD_COMMIT^ SHA1_OF_BAD_COMMIT
-$ git push -f [remote] [branch]
-```
-
-或者做一个 [交互式 rebase](#interactive-rebase) 删除那些你想要删除的提交(commit)里所对应的行。
-
-### 我尝试推一个修正后的提交(amended commit)到远程,但是报错:
-
-```bash
-To https://github.com/yourusername/repo.git
-! [rejected] mybranch -> mybranch (non-fast-forward)
-error: failed to push some refs to 'https://github.com/tanay1337/webmaker.org.git'
-hint: Updates were rejected because the tip of your current branch is behind
-hint: its remote counterpart. Integrate the remote changes (e.g.
-hint: 'git pull ...') before pushing again.
-hint: See the 'Note about fast-forwards' in 'git push --help' for details.
-```
-
-注意, rebasing(见下面)和修正(amending)会用一个**新的提交(commit)代替旧的**, 所以如果之前你已经往远程仓库上推过一次修正前的提交(commit),那你现在就必须强推(force push) (`-f`)。 注意 – _总是_ 确保你指明一个分支!
-
-```bash
-(my-branch)$ git push origin mybranch -f
-```
-
-一般来说, **要避免强推**. 最好是创建和推(push)一个新的提交(commit),而不是强推一个修正后的提交。后者会使那些与该分支或该分支的子分支工作的开发者,在源历史中产生冲突。
-
-### 我意外的做了一次硬重置(hard reset),我想找回我的内容
-
-如果你意外的做了 `git reset --hard`, 你通常能找回你的提交(commit), 因为 Git 对每件事都会有日志,且都会保存几天。
-
-```bash
-(master)$ git reflog
-```
-
-你将会看到一个你过去提交(commit)的列表, 和一个重置的提交。 选择你想要回到的提交(commit)的 SHA,再重置一次:
-
-```bash
-(master)$ git reset --hard SHA1234
-```
-
-这样就完成了。
-
-## 暂存(Staging)
-
-### 我需要把暂存的内容添加到上一次的提交(commit)
-
-```bash
-(my-branch*)$ git commit --amend
-
-```
-
-### 我想要暂存一个新文件的一部分,而不是这个文件的全部
-
-一般来说, 如果你想暂存一个文件的一部分, 你可这样做:
-
-```bash
-$ git add --patch filename.x
-```
-
-`-p` 简写。这会打开交互模式, 你将能够用 `s` 选项来分隔提交(commit); 然而, 如果这个文件是新的, 会没有这个选择, 添加一个新文件时, 这样做:
-
-```bash
-$ git add -N filename.x
-```
-
-然后, 你需要用 `e` 选项来手动选择需要添加的行,执行 `git diff --cached` 将会显示哪些行暂存了哪些行只是保存在本地了。
-
-### 我想把在一个文件里的变化(changes)加到两个提交(commit)里
-
-`git add` 会把整个文件加入到一个提交. `git add -p` 允许交互式的选择你想要提交的部分.
-
-### 我想把暂存的内容变成未暂存,把未暂存的内容暂存起来
-
-这个有点困难, 我能想到的最好的方法是先 stash 未暂存的内容, 然后重置(reset),再 pop 第一步 stashed 的内容, 最后再 add 它们。
-
-```bash
-$ git stash -k
-$ git reset --hard
-$ git stash pop
-$ git add -A
-```
-
-## 未暂存(Unstaged)的内容
-
-### 我想把未暂存的内容移动到一个新分支
-
-```bash
-$ git checkout -b my-branch
-```
-
-### 我想把未暂存的内容移动到另一个已存在的分支
-
-```bash
-$ git stash
-$ git checkout my-branch
-$ git stash pop
-```
-
-### 我想丢弃本地未提交的变化(uncommitted changes)
-
-如果你只是想重置源(origin)和你本地(local)之间的一些提交(commit),你可以:
-
-```bash
-# one commit
-(my-branch)$ git reset --hard HEAD^
-# two commits
-(my-branch)$ git reset --hard HEAD^^
-# four commits
-(my-branch)$ git reset --hard HEAD~4
-# or
-(master)$ git checkout -f
-```
-
-重置某个特殊的文件, 你可以用文件名做为参数:
-
-```bash
-$ git reset filename
-```
-
-### 我想丢弃某些未暂存的内容
-
-如果你想丢弃工作拷贝中的一部分内容,而不是全部。
-
-签出(checkout)不需要的内容,保留需要的。
-
-```bash
-$ git checkout -p
-# Answer y to all of the snippets you want to drop
-```
-
-另外一个方法是使用 `stash`, Stash 所有要保留下的内容, 重置工作拷贝, 重新应用保留的部分。
-
-```bash
-$ git stash -p
-# Select all of the snippets you want to save
-$ git reset --hard
-$ git stash pop
-```
-
-或者, stash 你不需要的部分, 然后 stash drop。
-
-```bash
-$ git stash -p
-# Select all of the snippets you don't want to save
-$ git stash drop
-```
-
-## 分支(Branches)
-
-### 我从错误的分支拉取了内容,或把内容拉取到了错误的分支
-
-这是另外一种使用 `git reflog` 情况,找到在这次错误拉(pull) 之前 HEAD 的指向。
-
-```bash
-(master)$ git reflog
-ab7555f HEAD@{0}: pull origin wrong-branch: Fast-forward
-c5bc55a HEAD@{1}: checkout: checkout message goes here
-```
-
-重置分支到你所需的提交(desired commit):
-
-```bash
-$ git reset --hard c5bc55a
-```
-
-完成。
-
-### 我想扔掉本地的提交(commit),以便我的分支与远程的保持一致
-
-先确认你没有推(push)你的内容到远程。
-
-`git status` 会显示你领先(ahead)源(origin)多少个提交:
-
-```bash
-(my-branch)$ git status
-# On branch my-branch
-# Your branch is ahead of 'origin/my-branch' by 2 commits.
-# (use "git push" to publish your local commits)
-#
-```
-
-一种方法是:
-
-```bash
-(master)$ git reset --hard origin/my-branch
-```
-
-### 我需要提交到一个新分支,但错误的提交到了 master
-
-在 master 下创建一个新分支,不切换到新分支,仍在 master 下:
-
-```bash
-(master)$ git branch my-branch
-```
-
-把 master 分支重置到前一个提交:
-
-```bash
-(master)$ git reset --hard HEAD^
-```
-
-`HEAD^` 是 `HEAD^1` 的简写,你可以通过指定要设置的`HEAD`来进一步重置。
-
-或者, 如果你不想使用 `HEAD^`, 找到你想重置到的提交(commit)的 hash(`git log` 能够完成), 然后重置到这个 hash。 使用`git push` 同步内容到远程。
-
-例如, master 分支想重置到的提交的 hash 为`a13b85e`:
-
-```bash
-(master)$ git reset --hard a13b85e
-HEAD is now at a13b85e
-```
-
-签出(checkout)刚才新建的分支继续工作:
-
-```bash
-(master)$ git checkout my-branch
-```
-
-### 我想保留来自另外一个 ref-ish 的整个文件
-
-假设你正在做一个原型方案(原文为 working spike (see note)), 有成百的内容,每个都工作得很好。现在, 你提交到了一个分支,保存工作内容:
-
-```bash
-(solution)$ git add -A && git commit -m "Adding all changes from this spike into one big commit."
-```
-
-当你想要把它放到一个分支里 (可能是`feature`, 或者 `develop`), 你关心是保持整个文件的完整,你想要一个大的提交分隔成比较小。
-
-假设你有:
-
-- 分支 `solution`, 拥有原型方案, 领先 `develop` 分支。
-- 分支 `develop`, 在这里你应用原型方案的一些内容。
-
-我去可以通过把内容拿到你的分支里,来解决这个问题:
-
-```bash
-(develop)$ git checkout solution -- file1.txt
-```
-
-这会把这个文件内容从分支 `solution` 拿到分支 `develop` 里来:
-
-```bash
-# On branch develop
-# Your branch is up-to-date with 'origin/develop'.
-# Changes to be committed:
-# (use "git reset HEAD ..." to unstage)
-#
-# modified: file1.txt
-```
-
-然后, 正常提交。
-
-Note: Spike solutions are made to analyze or solve the problem. These solutions are used for estimation and discarded once everyone gets clear visualization of the problem. \~ [Wikipedia](https://en.wikipedia.org/wiki/Extreme_programming_practices).
-
-### 我把几个提交(commit)提交到了同一个分支,而这些提交应该分布在不同的分支里
-
-假设你有一个`master`分支, 执行`git log`, 你看到你做过两次提交:
-
-```bash
-(master)$ git log
-
-commit e3851e817c451cc36f2e6f3049db528415e3c114
-Author: Alex Lee
-Date: Tue Jul 22 15:39:27 2014 -0400
-
- Bug #21 - Added CSRF protection
-
-commit 5ea51731d150f7ddc4a365437931cd8be3bf3131
-Author: Alex Lee
-Date: Tue Jul 22 15:39:12 2014 -0400
-
- Bug #14 - Fixed spacing on title
-
-commit a13b85e984171c6e2a1729bb061994525f626d14
-Author: Aki Rose
-Date: Tue Jul 21 01:12:48 2014 -0400
-
- First commit
-```
-
-让我们用提交 hash(commit hash)标记 bug (`e3851e8` for #21, `5ea5173` for #14).
-
-首先, 我们把`master`分支重置到正确的提交(`a13b85e`):
-
-```bash
-(master)$ git reset --hard a13b85e
-HEAD is now at a13b85e
-```
-
-现在, 我们对 bug #21 创建一个新的分支:
-
-```bash
-(master)$ git checkout -b 21
-(21)$
-```
-
-接着, 我们用 _cherry-pick_ 把对 bug #21 的提交放入当前分支。 这意味着我们将应用(apply)这个提交(commit),仅仅这一个提交(commit),直接在 HEAD 上面。
-
-```bash
-(21)$ git cherry-pick e3851e8
-```
-
-这时候, 这里可能会产生冲突, 参见[交互式 rebasing 章](#interactive-rebase) [**冲突节**](#merge-conflict) 解决冲突.
-
-再者, 我们为 bug #14 创建一个新的分支, 也基于`master`分支
-
-```bash
-(21)$ git checkout master
-(master)$ git checkout -b 14
-(14)$
-```
-
-最后, 为 bug #14 执行 `cherry-pick`:
-
-```bash
-(14)$ git cherry-pick 5ea5173
-```
-
-### 我想删除上游(upstream)分支被删除了的本地分支
-
-一旦你在 github 上面合并(merge)了一个 pull request, 你就可以删除你 fork 里被合并的分支。 如果你不准备继续在这个分支里工作, 删除这个分支的本地拷贝会更干净,使你不会陷入工作分支和一堆陈旧分支的混乱之中。
-
-```bash
-$ git fetch -p
-```
-
-### 我不小心删除了我的分支
-
-如果你定期推送到远程, 多数情况下应该是安全的,但有些时候还是可能删除了还没有推到远程的分支。 让我们先创建一个分支和一个新的文件:
-
-```bash
-(master)$ git checkout -b my-branch
-(my-branch)$ git branch
-(my-branch)$ touch foo.txt
-(my-branch)$ ls
-README.md foo.txt
-```
-
-添加文件并做一次提交
-
-```bash
-(my-branch)$ git add .
-(my-branch)$ git commit -m 'foo.txt added'
-(my-branch)$ foo.txt added
- 1 files changed, 1 insertions(+)
- create mode 100644 foo.txt
-(my-branch)$ git log
-
-commit 4e3cd85a670ced7cc17a2b5d8d3d809ac88d5012
-Author: siemiatj
-Date: Wed Jul 30 00:34:10 2014 +0200
-
- foo.txt added
-
-commit 69204cdf0acbab201619d95ad8295928e7f411d5
-Author: Kate Hudson
-Date: Tue Jul 29 13:14:46 2014 -0400
-
- Fixes #6: Force pushing after amending commits
-```
-
-现在我们切回到主(master)分支,‘不小心的’删除`my-branch`分支
-
-```bash
-(my-branch)$ git checkout master
-Switched to branch 'master'
-Your branch is up-to-date with 'origin/master'.
-(master)$ git branch -D my-branch
-Deleted branch my-branch (was 4e3cd85).
-(master)$ echo oh noes, deleted my branch!
-oh noes, deleted my branch!
-```
-
-在这时候你应该想起了`reflog`, 一个升级版的日志,它存储了仓库(repo)里面所有动作的历史。
-
-```
-(master)$ git reflog
-69204cd HEAD@{0}: checkout: moving from my-branch to master
-4e3cd85 HEAD@{1}: commit: foo.txt added
-69204cd HEAD@{2}: checkout: moving from master to my-branch
-```
-
-正如你所见,我们有一个来自删除分支的提交 hash(commit hash),接下来看看是否能恢复删除了的分支。
-
-```bash
-(master)$ git checkout -b my-branch-help
-Switched to a new branch 'my-branch-help'
-(my-branch-help)$ git reset --hard 4e3cd85
-HEAD is now at 4e3cd85 foo.txt added
-(my-branch-help)$ ls
-README.md foo.txt
-```
-
-看! 我们把删除的文件找回来了。 Git 的 `reflog` 在 rebasing 出错的时候也是同样有用的。
-
-### 我想删除一个分支
-
-删除一个远程分支:
-
-```bash
-(master)$ git push origin --delete my-branch
-```
-
-你也可以:
-
-```bash
-(master)$ git push origin :my-branch
-```
-
-删除一个本地分支:
-
-```bash
-(master)$ git branch -D my-branch
-```
-
-### 我想从别人正在工作的远程分支签出(checkout)一个分支
-
-首先, 从远程拉取(fetch) 所有分支:
-
-```bash
-(master)$ git fetch --all
-```
-
-假设你想要从远程的`daves`分支签出到本地的`daves`
-
-```bash
-(master)$ git checkout --track origin/daves
-Branch daves set up to track remote branch daves from origin.
-Switched to a new branch 'daves'
-```
-
-(`--track` 是 `git checkout -b [branch] [remotename]/[branch]` 的简写)
-
-这样就得到了一个`daves`分支的本地拷贝, 任何推过(pushed)的更新,远程都能看到.
-
-## Rebasing 和合并(Merging)
-
-### 我想撤销 rebase/merge
-
-你可以合并(merge)或 rebase 了一个错误的分支, 或者完成不了一个进行中的 rebase/merge。 Git 在进行危险操作的时候会把原始的 HEAD 保存在一个叫 ORIG_HEAD 的变量里, 所以要把分支恢复到 rebase/merge 前的状态是很容易的。
-
-```bash
-(my-branch)$ git reset --hard ORIG_HEAD
-```
-
-### 我已经 rebase 过, 但是我不想强推(force push)
-
-不幸的是,如果你想把这些变化(changes)反应到远程分支上,你就必须得强推(force push)。 是因你快进(Fast forward)了提交,改变了 Git 历史, 远程分支不会接受变化(changes),除非强推(force push)。这就是许多人使用 merge 工作流, 而不是 rebasing 工作流的主要原因之一, 开发者的强推(force push)会使大的团队陷入麻烦。使用时需要注意,一种安全使用 rebase 的方法是,不要把你的变化(changes)反映到远程分支上, 而是按下面的做:
-
-```bash
-(master)$ git checkout my-branch
-(my-branch)$ git rebase -i master
-(my-branch)$ git checkout master
-(master)$ git merge --ff-only my-branch
-```
-
-更多, 参见 [this SO thread](http://stackoverflow.com/questions/11058312/how-can-i-use-git-rebase-without-requiring-a-forced-push).
-
-### 我需要组合(combine)几个提交(commit)
-
-假设你的工作分支将会做对于 `master` 的 pull-request。 一般情况下你不关心提交(commit)的时间戳,只想组合 _所有_ 提交(commit) 到一个单独的里面, 然后重置(reset)重提交(recommit)。 确保主(master)分支是最新的和你的变化都已经提交了, 然后:
-
-```bash
-(my-branch)$ git reset --soft master
-(my-branch)$ git commit -am "New awesome feature"
-```
-
-如果你想要更多的控制, 想要保留时间戳, 你需要做交互式 rebase (interactive rebase):
-
-```bash
-(my-branch)$ git rebase -i master
-```
-
-如果没有相对的其它分支, 你将不得不相对自己的`HEAD` 进行 rebase。 例如:你想组合最近的两次提交(commit), 你将相对于`HEAD\~2` 进行 rebase, 组合最近 3 次提交(commit), 相对于`HEAD\~3`, 等等。
-
-```bash
-(master)$ git rebase -i HEAD~2
-```
-
-在你执行了交互式 rebase 的命令(interactive rebase command)后, 你将在你的编辑器里看到类似下面的内容:
-
-```vim
-pick a9c8a1d Some refactoring
-pick 01b2fd8 New awesome feature
-pick b729ad5 fixup
-pick e3851e8 another fix
-
-# Rebase 8074d12..b729ad5 onto 8074d12
-#
-# Commands:
-# p, pick = use commit
-# r, reword = use commit, but edit the commit message
-# e, edit = use commit, but stop for amending
-# s, squash = use commit, but meld into previous commit
-# f, fixup = like "squash", but discard this commit's log message
-# x, exec = run command (the rest of the line) using shell
-#
-# These lines can be re-ordered; they are executed from top to bottom.
-#
-# If you remove a line here THAT COMMIT WILL BE LOST.
-#
-# However, if you remove everything, the rebase will be aborted.
-#
-# Note that empty commits are commented out
-```
-
-所有以 `#` 开头的行都是注释, 不会影响 rebase.
-
-然后,你可以用任何上面命令列表的命令替换 `pick`, 你也可以通过删除对应的行来删除一个提交(commit)。
-
-例如, 如果你想 **单独保留最旧(first)的提交(commit),组合所有剩下的到第二个里面**, 你就应该编辑第二个提交(commit)后面的每个提交(commit) 前的单词为 `f`:
-
-```vim
-pick a9c8a1d Some refactoring
-pick 01b2fd8 New awesome feature
-f b729ad5 fixup
-f e3851e8 another fix
-```
-
-如果你想组合这些提交(commit) **并重命名这个提交(commit)**, 你应该在第二个提交(commit)旁边添加一个`r`,或者更简单的用`s` 替代 `f`:
-
-```vim
-pick a9c8a1d Some refactoring
-pick 01b2fd8 New awesome feature
-s b729ad5 fixup
-s e3851e8 another fix
-```
-
-你可以在接下来弹出的文本提示框里重命名提交(commit)。
-
-```vim
-Newer, awesomer features
-
-# Please enter the commit message for your changes. Lines starting
-# with '#' will be ignored, and an empty message aborts the commit.
-# rebase in progress; onto 8074d12
-# You are currently editing a commit while rebasing branch 'master' on '8074d12'.
-#
-# Changes to be committed:
-# modified: README.md
-#
-
-```
-
-如果成功了, 你应该看到类似下面的内容:
-
-```bash
-(master)$ Successfully rebased and updated refs/heads/master.
-```
-
-#### 安全合并(merging)策略
-
-`--no-commit` 执行合并(merge)但不自动提交, 给用户在做提交前检查和修改的机会。 `no-ff` 会为特性分支(feature branch)的存在过留下证据, 保持项目历史一致。
-
-```bash
-(master)$ git merge --no-ff --no-commit my-branch
-```
-
-#### 我需要将一个分支合并成一个提交(commit)
-
-```bash
-(master)$ git merge --squash my-branch
-```
-
-#### 我只想组合(combine)未推的提交(unpushed commit)
-
-有时候,在将数据推向上游之前,你有几个正在进行的工作提交(commit)。这时候不希望把已经推(push)过的组合进来,因为其他人可能已经有提交(commit)引用它们了。
-
-```bash
-(master)$ git rebase -i @{u}
-```
-
-这会产生一次交互式的 rebase(interactive rebase), 只会列出没有推(push)的提交(commit), 在这个列表时进行 reorder/fix/squash 都是安全的。
-
-### 检查是否分支上的所有提交(commit)都合并(merge)过了
-
-检查一个分支上的所有提交(commit)是否都已经合并(merge)到了其它分支, 你应该在这些分支的 head(或任何 commits)之间做一次 diff:
-
-```bash
-(master)$ git log --graph --left-right --cherry-pick --oneline HEAD...feature/120-on-scroll
-```
-
-这会告诉你在一个分支里有而另一个分支没有的所有提交(commit), 和分支之间不共享的提交(commit)的列表。 另一个做法可以是:
-
-```bash
-(master)$ git log master ^feature/120-on-scroll --no-merges
-```
-
-### 交互式 rebase(interactive rebase)可能出现的问题
-
-#### 这个 rebase 编辑屏幕出现'noop'
-
-如果你看到的是这样:
-
-```
-noop
-```
-
-这意味着你 rebase 的分支和当前分支在同一个提交(commit)上, 或者 _领先(ahead)_ 当前分支。 你可以尝试:
-
-- 检查确保主(master)分支没有问题
-- rebase `HEAD\~2` 或者更早
-
-#### 有冲突的情况
-
-如果你不能成功的完成 rebase, 你可能必须要解决冲突。
-
-首先执行 `git status` 找出哪些文件有冲突:
-
-```bash
-(my-branch)$ git status
-On branch my-branch
-Changes not staged for commit:
- (use "git add ..." to update what will be committed)
- (use "git checkout -- ..." to discard changes in working directory)
-
- modified: README.md
-```
-
-在这个例子里面, `README.md` 有冲突。 打开这个文件找到类似下面的内容:
-
-```vim
- <<<<<<< HEAD
- some code
- =========
- some code
- >>>>>>> new-commit
-```
-
-你需要解决新提交的代码(示例里, 从中间`==`线到`new-commit`的地方)与`HEAD` 之间不一样的地方.
-
-有时候这些合并非常复杂,你应该使用可视化的差异编辑器(visual diff editor):
-
-```bash
-(master*)$ git mergetool -t opendiff
-```
-
-在你解决完所有冲突和测试过后, `git add` 变化了的(changed)文件, 然后用`git rebase --continue` 继续 rebase。
-
-```bash
-(my-branch)$ git add README.md
-(my-branch)$ git rebase --continue
-```
-
-如果在解决完所有的冲突过后,得到了与提交前一样的结果, 可以执行`git rebase --skip`。
-
-任何时候你想结束整个 rebase 过程,回来 rebase 前的分支状态, 你可以做:
-
-```bash
-(my-branch)$ git rebase --abort
-```
-
-## 杂项(Miscellaneous Objects)
-
-### 克隆所有子模块
-
-```bash
-$ git clone --recursive git://github.com/foo/bar.git
-```
-
-如果已经克隆了:
-
-```bash
-$ git submodule update --init --recursive
-```
-
-### 删除标签(tag)
-
-```bash
-$ git tag -d
-$ git push :refs/tags/
-```
-
-### 恢复已删除标签(tag)
-
-如果你想恢复一个已删除标签(tag), 可以按照下面的步骤: 首先, 需要找到无法访问的标签(unreachable tag):
-
-```bash
-$ git fsck --unreachable | grep tag
-```
-
-记下这个标签(tag)的 hash,然后用 Git 的 [update-ref](http://git-scm.com/docs/git-update-ref):
-
-```bash
-$ git update-ref refs/tags/
-```
-
-这时你的标签(tag)应该已经恢复了。
-
-### 已删除补丁(patch)
-
-如果某人在 GitHub 上给你发了一个 pull request, 但是然后他删除了他自己的原始 fork, 你将没法克隆他们的提交(commit)或使用 `git am`。在这种情况下, 最好手动的查看他们的提交(commit),并把它们拷贝到一个本地新分支,然后做提交。
-
-做完提交后, 再修改作者,参见[变更作者](#commit-wrong-author)。 然后, 应用变化, 再发起一个新的 pull request。
-
-## 跟踪文件(Tracking Files)
-
-### 我只想改变一个文件名字的大小写,而不修改内容
-
-```bash
-(master)$ git mv --force myfile MyFile
-```
-
-### 我想从 Git 删除一个文件,但保留该文件
-
-```bash
-(master)$ git rm --cached log.txt
-```
-
-## 配置(Configuration)
-
-### 我想给一些 Git 命令添加别名(alias)
-
-在 OS X 和 Linux 下, 你的 Git 的配置文件储存在 `\~/.gitconfig`。我在`[alias]` 部分添加了一些快捷别名(和一些我容易拼写错误的),如下:
-
-```vim
-[alias]
- a = add
- amend = commit --amend
- c = commit
- ca = commit --amend
- ci = commit -a
- co = checkout
- d = diff
- dc = diff --changed
- ds = diff --staged
- f = fetch
- loll = log --graph --decorate --pretty=oneline --abbrev-commit
- m = merge
- one = log --pretty=oneline
- outstanding = rebase -i @{u}
- s = status
- unpushed = log @{u}
- wc = whatchanged
- wip = rebase -i @{u}
- zap = fetch -p
-```
-
-### 我想缓存一个仓库(repository)的用户名和密码
-
-你可能有一个仓库需要授权,这时你可以缓存用户名和密码,而不用每次推/拉(push/pull)的时候都输入,Credential helper 能帮你。
-
-```bash
-$ git config --global credential.helper cache
-# Set git to use the credential memory cache
-```
-
-```bash
-$ git config --global credential.helper 'cache --timeout=3600'
-# Set the cache to timeout after 1 hour (setting is in seconds)
-```
-
-## 我不知道我做错了些什么
-
-你把事情搞砸了:你 `重置(reset)` 了一些东西, 或者你合并了错误的分支, 亦或你强推了后找不到你自己的提交(commit)了。有些时候, 你一直都做得很好, 但你想回到以前的某个状态。
-
-这就是 `git reflog` 的目的, `reflog` 记录对分支顶端(the tip of a branch)的任何改变, 即使那个顶端没有被任何分支或标签引用。基本上, 每次 HEAD 的改变, 一条新的记录就会增加到`reflog`。遗憾的是,这只对本地分支起作用,且它只跟踪动作 (例如,不会跟踪一个没有被记录的文件的任何改变)。
-
-```bash
-(master)$ git reflog
-0a2e358 HEAD@{0}: reset: moving to HEAD\~2
-0254ea7 HEAD@{1}: checkout: moving from 2.2 to master
-c10f740 HEAD@{2}: checkout: moving from master to 2.2
-```
-
-上面的 reflog 展示了从 master 分支签出(checkout)到 2.2 分支,然后再签回。 那里,还有一个硬重置(hard reset)到一个较旧的提交。最新的动作出现在最上面以 `HEAD@{0}`标识.
-
-如果事实证明你不小心回移(move back)了提交(commit), reflog 会包含你不小心回移前 master 上指向的提交(0254ea7)。
-
-```bash
-$ git reset --hard 0254ea7
-```
-
-然后使用 git reset 就可以把 master 改回到之前的 commit,这提供了一个在历史被意外更改情况下的安全网。
-
-## 资源
-
-- https://github.com/k88hudson/git-flight-rules/blob/master/README_zh-CN.md
-- https://github.com/521xueweihan/git-tips
diff --git a/docs/git/git-flow.md b/docs/git/git-flow.md
deleted file mode 100644
index 604daddc..00000000
--- a/docs/git/git-flow.md
+++ /dev/null
@@ -1,252 +0,0 @@
-# git-flow 工作流
-
-## 集中式 vs 分布式
-
-在分布式版本控制工具 [**Git**](https://git-scm.com/) 之前,我一直用的是集中式版本控制工具,具体来说,我用过 **[ClearCase](http://www-03.ibm.com/software/products/en/clearcase)**(简称 cc)、**[Subversion](https://tortoisesvn.net/)**(简称 svn)。
-
-这里,结合我的一点个人经验,谈谈这几个工具的特点。
-
-### 集中式版本控制
-
-**[ClearCase](http://www-03.ibm.com/software/products/en/clearcase)** 是 IBM 的产品。IBM 的产品总给人一种过于重型化的感觉,似乎它们的产品什么都想做,结果反而让人觉得太复杂,不好用(想想曾经被 Notes 邮箱支配的恐惧吧)。**[ClearCase](http://www-03.ibm.com/software/products/en/clearcase)** 一如既往,功能复杂,但是操作很繁琐。
-
-**[Subversion](https://tortoisesvn.net/)** 由于 logo 是乌龟,所以也常被称为小乌龟。它的优点是:GUI 工具做的很细致,易于上手;安全控制和权限控制非常细粒度(目录级别的管控);对于特别大型的项目,每个开发者都拷贝完整的镜像到本地,会占用较大的磁盘空间,还不如将所有数据都存放在大型服务器上。
-
-### 分布式版本控制
-
-分布式版本控制工具当然不止 Git,但是受 Github 的影响,Git 无疑是最火,用户最广的工具。
-
-Git 的优点主要就体现在分布式设计上:
-
-- 支持离线工作。除了同步远程仓库,基本都是在本地完成工作。
-- 安全稳定。集中式版本控制工具,要求所有机器将每次修改都推送到中央服务器,一旦中央服务器宕机,所有人都不能工作。分布式版本控制工具的每台机器克隆远程仓库到本地后,都拥有完整的镜像,一台机器宕机,不影响其他人工作,而且数据容易恢复。
-- Git 自身有着优秀的分支模型,拉分支、打标签都非常便捷。
-
-### 小结
-
-**[ClearCase](http://www-03.ibm.com/software/products/en/clearcase)** 比较难用,谁用谁知道。
-
-**[Subversion](https://tortoisesvn.net/)** 由于自身的优点,还是有不少公司仍在使用的。不能说不使用分布式版本控制就一定是 out 了,很多时候也是基于公司应用场景的考量(大公司往往更看重安全和权限控制)。个人认为 svn 还是挺好用的,除了拉分支确实比较麻烦些,但这也是基于 svn 本身权限控制的考虑。
-
-[**Git**](https://git-scm.com/) 由于其开源免费、分布式特性,深受互联网公司的青睐。
-
-## 版本管理的挑战
-
-Git 是一个非常优秀的版本控制工具,但是在实际版本管理中,仍然会遇到一些问题:
-
-1. 如何开始一个Feature的开发,而不影响别的Feature?
-2. 由于很容易创建新分支,分支多了如何管理,时间久了,如何知道每个分支是干什么的?
-3. 哪些分支已经合并回了主干?
-4. 如何进行Release的管理?开始一个Release的时候如何冻结Feature, 如何在Prepare Release的时候,开发人员可以继续开发新的功能?
-5. 线上代码出Bug了,如何快速修复?而且修复的代码要包含到开发人员的分支以及下一个Release?
-
-大部分开发人员现在使用Git就只是用三个甚至两个分支,一个是Master, 一个是Develop, 还有一个是基于Develop打得各种分支。这个在小项目规模的时候还勉强可以支撑,因为很多人做项目就只有一个Release, 但是人员一多,而且项目周期一长就会出现各种问题。
-
-## git-flow 模型
-
-[Vincent Driessen](http://nvie.com/about/) 同学发表了博客 [A successful Git branching model](http://nvie.com/git-model) ,文章讲解了他是如何让自己的[Git](http://www.oschina.net/p/git)仓库保持整洁,除此之外,他发布了git-flow; 一个可以轻松实现该模型的Git扩展。
-
-这个最佳实践已经成为最为流行的 git 分支模型,一些 GUI 工具甚至已经支持建立这种模型。
-
-下面,来介绍一下 git-flow 模型。
-
-
-
-`Gitflow`工作流仍然用中央仓库作为所有开发者的交互中心。和其它的工作流一样,开发者在本地工作并`push`分支到要中央仓库中。
-
-### 核心分支
-
-`Gitflow`工作流使用2个分支来记录项目的历史。
-
-`master` 分支对应线上实际的发布版本。
-
-`develop` 分支作为功能的集成分支。
-
-
-
-### 功能分支
-
-每个新功能位于一个自己的分支,这样可以[`push`到中央仓库以备份和协作](https://www.atlassian.com/git/tutorial/remote-repositories#!push)。但功能分支不是从`master`分支上拉出新分支,而是使用`develop`分支作为父分支。当新功能完成时,[合并回`develop`分支](https://www.atlassian.com/git/tutorial/git-branches#!merge)。新功能提交应该从不直接与`master`分支交互。
-
-
-
-注意,从各种含义和目的上来看,功能分支加上`develop`分支就是功能分支工作流的用法。但`Gitflow`工作流没有在这里止步。
-
-### 发布分支
-
-
-
-一旦`develop`分支上有了做一次发布(或者说快到了既定的发布日)的足够功能,就从`develop`分支上`fork`一个发布分支。新建的分支用于开始发布循环,所以从这个时间点开始之后新的功能不能再加到这个分支上 —— 这个分支只应该做`Bug`修复、文档生成和其它面向发布任务。一旦对外发布的工作都完成了,发布分支合并到`master`分支并分配一个版本号打好`Tag`。另外,这些从新建发布分支以来的做的修改要合并回`develop`分支。
-
-使用一个用于发布准备的专门分支,使得一个团队可以在完善当前的发布版本的同时,另一个团队可以继续开发下个版本的功能。
-这也打造定义良好的开发阶段(比如,可以很轻松地说,『这周我们要做准备发布版本4.0』,并且在仓库的目录结构中可以实际看到)。
-
-常用的分支约定:
-
-`用于新建发布分支的分支: develop用于合并的分支: master分支命名: release-* 或 release/*`
-
-### 维护分支
-
-
-
-维护分支或说是热修复(`hotfix`)分支用于生成快速给产品发布版本(`production releases`)打补丁,这是唯一可以直接从`master`分支`fork`出来的分支。修复完成,修改应该马上合并回`master`分支和`develop`分支(当前的发布分支),`master`分支应该用新的版本号打好`Tag`。
-
-为`Bug`修复使用专门分支,让团队可以处理掉问题而不用打断其它工作或是等待下一个发布循环。你可以把维护分支想成是一个直接在`master`分支上处理的临时发布。
-
-## git-flow 代码示例
-
-a. 创建develop分支
-
-```bash
-git branch develop
-git push -u origin develop
-```
-
-b. 开始新Feature开发
-
-```bash
-git checkout -b some-feature develop
-# Optionally, push branch to origin:
-git push -u origin some-feature
-
-# 做一些改动
-git status
-git add some-file
-git commit
-```
-
-c. 完成Feature
-
-```bash
-git pull origin develop
-git checkout develop
-git merge --no-ff some-feature
-git push origin develop
-
-git branch -d some-feature
-
-# If you pushed branch to origin:
-git push origin --delete some-feature
-```
-
-d. 开始Relase
-
-```bash
-git checkout -b release-0.1.0 develop
-
-# Optional: Bump version number, commit
-# Prepare release, commit
-```
-
-e. 完成Release
-
-```bash
-git checkout master
-git merge --no-ff release-0.1.0
-git push
-
-git checkout develop
-git merge --no-ff release-0.1.0
-git push
-
-git branch -d release-0.1.0
-
-# If you pushed branch to origin:
-git push origin --delete release-0.1.0
-
-
-git tag -a v0.1.0 master
-git push --tags
-```
-
-f. 开始Hotfix
-
-```bash
-git checkout -b hotfix-0.1.1 master
-```
-
-g. 完成Hotfix
-
-```bash
-git checkout master
-git merge --no-ff hotfix-0.1.1
-git push
-
-
-git checkout develop
-git merge --no-ff hotfix-0.1.1
-git push
-
-git branch -d hotfix-0.1.1
-
-git tag -a v0.1.1 master
-git push --tags
-```
-
-## git-flow 工具
-
-实际上,当你理解了上面的流程后,你完全不用使用工具,但是实际上我们大部分人很多命令就是记不住呀,流程就是记不住呀,肿么办呢?
-
-总有聪明的人创造好的工具给大家用, 那就是Git flow script.
-
-### git-flow
-
-#### 安装
-
-你需要有一个可以工作的 git 作为前提。
-
-Git flow 可以工作在 OSX, Linux 和 Windows之下
-
-- OSX Homebrew
-
-```
-$ brew install git-flow
-```
-
-- OSX Macports
-
-```
-$ port install git-flow
-```
-
-- Linux
-
-```
-$ apt-get install git-flow
-```
-
-- Windows (Cygwin):
-
-安装 git-flow, 你需要 wget 和 util-linux。
-
-```
-$ wget -q -O - --no-check-certificate https://github.com/nvie/gitflow/raw/develop/contrib/gitflow-installer.sh | bash
-```
-
-#### 使用
-
-- **初始化:** git flow init
-- **开始新Feature:** git flow feature start MYFEATURE
-- **Publish一个Feature(也就是push到远程):** git flow feature publish MYFEATURE
-- **获取Publish的Feature:** git flow feature pull origin MYFEATURE
-- **完成一个Feature:** git flow feature finish MYFEATURE
-- **开始一个Release:** git flow release start RELEASE [BASE]
-- **Publish一个Release:** git flow release publish RELEASE
-- **发布Release:** git flow release finish RELEASE
- 别忘了git push --tags
-- **开始一个Hotfix:** git flow hotfix start VERSION [BASENAME]
-- **发布一个Hotfix:** git flow hotfix finish VERSION
-
-
-
-### Source Tree
-
-[Source Tree](https://www.sourcetreeapp.com/) 支持Mac, Windows, Linux,是一个不过的 git-flow GUI 工具。
-
-## 资料
-
-[git 官网](https://git-scm.com/) | [git 官方 Github](https://github.com/git/git)
-
-[廖雪峰的 git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
-
-[https://github.com/arslanbilal/git-cheat-sheet/blob/master/other-sheets/git-cheat-sheet-zh.md](https://github.com/arslanbilal/git-cheat-sheet/blob/master/other-sheets/git-cheat-sheet-zh.md)
diff --git a/docs/git/git-quickstart.md b/docs/git/git-quickstart.md
deleted file mode 100644
index 1e19597d..00000000
--- a/docs/git/git-quickstart.md
+++ /dev/null
@@ -1,520 +0,0 @@
-# Git 快速指南
-
-## 简介
-
-### Git 是什么?
-
-Git 是一个开源的分布式版本控制系统。
-
-### 什么是版本控制?
-
-版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。
-
-### 什么是分布式版本控制系统?
-
-介绍分布式版本控制系统前,有必要先了解一下传统的集中式版本控制系统。
-
-**集中化的版本控制系统**,诸如 CVS,Subversion 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。
-
-这么做最显而易见的缺点是中央服务器的单点故障。如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。要是中央服务器的磁盘发生故障,碰巧没做备份,或者备份不够及时,就会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录。
-
-
-
-**分布式版本控制系统**的客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份。
-
-
-
-### 为什么使用 Git?
-
-Git 是分布式的。这是 Git 和其它非分布式的版本控制系统,例如 svn,cvs 等,最核心的区别。分布式带来以下好处:
-
-**工作时不需要联网**
-
-首先,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件 A,你的同事也在他的电脑上改了文件 A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
-
-**更加安全**
-
-集中式版本控制系统,一旦中央服务器出了问题,所有人都无法工作。
-
-分布式版本控制系统,每个人电脑中都有完整的版本库,所以某人的机器挂了,并不影响其它人。
-
-## 原理
-
-### 版本库
-
-当你一个项目到本地或创建一个 git 项目,项目目录下会有一个隐藏的 `.git` 子目录。这个目录是 git 用来跟踪管理版本库的,千万不要手动修改。
-
-### 哈希值
-
-Git 中所有数据在存储前都计算校验和,然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。
-
-Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。 这是一个由 40 个十六进制字符(0-9 和 a-f)组成字符串,基于 Git 中文件的内容或目录结构计算出来。 SHA-1 哈希看起来是这样:
-
-```
-24b9da6552252987aa493b52f8696cd6d3b00373
-```
-
-Git 中使用这种哈希值的情况很多,你将经常看到这种哈希值。 实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。
-
-### 文件状态
-
-在 GIt 中,你的文件可能会处于三种状态之一:
-
-- **已修改(modified)**
-
- 已修改表示修改了文件,但还没保存到数据库中。
-
-- **已暂存(staged)**
-
- 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
-
-- **已提交(committed)**
-
- 已提交表示数据已经安全的保存在本地数据库中。
-
-### 工作区域
-
-与文件状态对应的,不同状态的文件在 Git 中处于不同的工作区域。
-
-- **工作区(working)**
-
- 当你 `git clone` 一个项目到本地,相当于在本地克隆了项目的一个副本。
-
- 工作区是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
-
-* **暂存区(staging)**
-
- 暂存区是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。 有时候也被称作`‘索引’',不过一般说法还是叫暂存区。
-
-- **本地仓库(local)**
-
- 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 本地仓库。
-
-- **远程仓库(remote)**
-
- 以上几个工作区都是在本地。为了让别人可以看到你的修改,你需要将你的更新推送到远程仓库。
-
- 同理,如果你想同步别人的修改,你需要从远程仓库拉取更新。
-
-
-
-## 安装
-
-### Linux
-
-#### Debian/Ubuntu
-
-如果你使用的系统是 Debian/Ubuntu , 安装命令为:
-
-```bash
-$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
-> libz-dev libssl-dev
-$ apt-get install git-core
-$ git --version
-git version 1.8.1.2
-```
-
-#### Centos/RedHat
-
-如果你使用的系统是 Centos/RedHat ,安装命令为:
-
-```bash
-$ yum install curl-devel expat-devel gettext-devel \
-> openssl-devel zlib-devel
-$ yum -y install git-core
-$ git --version
-git version 1.7.1
-```
-
-### Windows
-
-在[Git 官方下载地址](https://git-scm.com/downloads)下载 exe 安装包。按照安装向导安装即可。
-
-建议安装 Git Bash 这个 git 的命令行工具。
-
-### Mac
-
-在[Git 官方下载地址](https://git-scm.com/downloads)下载 mac 安装包。按照安装向导安装即可。
-
-## 配置
-
-Git 自带一个 `git config` 的工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置:
-
-1. `/etc/gitconfig` 文件: 包含系统上每一个用户及他们仓库的通用配置。 如果使用带有 `--system` 选项的 `git config` 时,它会从此文件读写配置变量。
-2. `\~/.gitconfig` 或 `\~/.config/git/config` 文件:只针对当前用户。 可以传递 `--global` 选项让 Git 读写此文件。
-3. 当前使用仓库的 Git 目录中的 `config` 文件(就是 `.git/config`):针对该仓库。
-
-每一个级别覆盖上一级别的配置,所以 `.git/config` 的配置变量会覆盖 `/etc/gitconfig` 中的配置变量。
-
-在 Windows 系统中,Git 会查找 `$HOME` 目录下(一般情况下是 `C:\Users\$USER`)的 `.gitconfig` 文件。 Git 同样也会寻找 `/etc/gitconfig` 文件,但只限于 MSys 的根目录下,即安装 Git 时所选的目标位置。
-
-### 用户信息
-
-当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址。 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改:
-
-```
-$ git config --global user.name "John Doe"
-$ git config --global user.email johndoe@example.com
-```
-
-再次强调,如果使用了 `--global` 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 `--global` 选项的命令来配置。
-
-很多 GUI 工具都会在第一次运行时帮助你配置这些信息。
-
-### .gitignore
-
-`.gitignore` 文件可能从字面含义也不难猜出:这个文件里配置的文件或目录,会自动被 git 所忽略,不纳入版本控制。
-
-在日常开发中,我们的项目经常会产生一些临时文件,如编译 Java 产生的 `*.class` 文件,又或是 IDE 自动生成的隐藏目录(Intellij 的 `.idea` 目录、Eclipse 的 `.settings` 目录等)等等。这些文件或目录实在没必要纳入版本管理。在这种场景下,你就需要用到 `.gitignore` 配置来过滤这些文件或目录。
-
-配置的规则很简单,也没什么可说的,看几个例子,自然就明白了。
-
-这里推荐一下 Github 的开源项目:https://github.com/github/gitignore
-
-在这里,你可以找到很多常用的模板,如:Java、Nodejs、C++ 的 `.gitignore` 模板等等。
-
-## 命令
-
-国外网友制作了一张 Git Cheat Sheet,总结很精炼,各位不妨收藏一下。
-
-本节选择性介绍 git 中比较常用的命令行场景。
-
-
-
-### 创建
-
-#### 克隆一个已创建的仓库
-
-```bash
-# 通过 SSH
-$ git clone ssh://user@domain.com/repo.git
-
-#通过 HTTP
-$ git clone http://domain.com/user/repo.git
-```
-
-#### 创建一个新的本地仓库
-
-```bash
-$ git init
-```
-
-### 添加修改
-
-#### 添加修改到暂存区
-
-```bash
-# 把指定文件添加到暂存区
-$ git add xxx
-
-# 把当前所有修改添加到暂存区
-$ git add .
-
-# 把所有修改添加到暂存区
-$ git add -A
-```
-
-#### 提交修改到本地仓库
-
-```bash
-# 提交本地的所有修改
-$ git commit -a
-
-# 提交之前已标记的变化
-$ git commit
-
-# 附加消息提交
-$ git commit -m 'commit message'
-```
-
-#### 储藏
-
-有时,我们需要在同一个项目的不同分支上工作。当需要切换分支时,偏偏本地的工作还没有完成,此时,提交修改显得不严谨,但是不提交代码又无法切换分支。这时,你可以使用 `git stash` 将本地的修改内容作为草稿储藏起来。
-
-官方称之为储藏,但我个人更喜欢称之为存草稿。
-
-```bash
-# 1. 将修改作为当前分支的草稿保存
-$ git stash
-
-# 2. 查看草稿列表
-$ git stash list
-stash@{0}: WIP on master: 6fae349 :memo: Writing docs.
-
-# 3.1 删除草稿
-$ git stash drop stash@{0}
-
-# 3.2 读取草稿
-$ git stash apply stash@{0}
-```
-
-### 撤销修改
-
-#### 撤销本地修改
-
-```bash
-# 移除缓存区的所有文件(i.e. 撤销上次git add)
-$ git reset HEAD
-
-# 将HEAD重置到上一次提交的版本,并将之后的修改标记为未添加到缓存区的修改
-$ git reset
-
-# 将HEAD重置到上一次提交的版本,并保留未提交的本地修改
-$ git reset --keep
-
-# 放弃工作目录下的所有修改
-$ git reset --hard HEAD
-
-# 将HEAD重置到指定的版本,并抛弃该版本之后的所有修改
-$ git reset --hard
-
-# 用远端分支强制覆盖本地分支
-$ git reset --hard e.g., upstream/master, origin/my-feature
-
-# 放弃某个文件的所有本地修改
-$ git checkout HEAD
-```
-
-##### 删除添加`.gitignore`文件前错误提交的文件
-
-```bash
-$ git rm -r --cached .
-$ git add .
-$ git commit -m "remove xyz file"
-```
-
-#### 撤销远程修改
-
-#### 创建一个新的提交,并回滚到指定版本
-
-```bash
-$ git revert
-```
-
-#### 彻底删除指定版本
-
-```bash
-# 执行下面命令后,commit-hash 提交后的记录都会被彻底删除,使用需谨慎
-$ git reset --hard
-$ git push -f
-```
-
-### 更新与推送
-
-#### 更新
-
-```bash
-# 下载远程端版本,但不合并到HEAD中
-$ git fetch
-
-# 将远程端版本合并到本地版本中
-$ git pull origin master
-
-# 以rebase方式将远端分支与本地合并
-$ git pull --rebase
-```
-
-#### 推送
-
-```bash
-# 将本地版本推送到远程端
-$ git push remote
-
-# 删除远程端分支
-$ git push : (since Git v1.5.0)
-$ git push --delete (since Git v1.7.0)
-
-# 发布标签
-$ git push --tags
-```
-
-### 查看信息
-
-#### 显示工作路径下已修改的文件
-
-```bash
-$ git status
-```
-
-#### 显示与上次提交版本文件的不同
-
-```bash
-$ git diff
-```
-
-#### 显示提交历史
-
-```bash
-# 从最新提交开始,显示所有的提交记录(显示hash, 作者信息,提交的标题和时间)
-$ git log
-
-# 显示某个用户的所有提交
-$ git log --author="username"
-
-# 显示某个文件的所有修改
-$ git log -p
-```
-
-#### 显示搜索内容
-
-```bash
-# 从当前目录的所有文件中查找文本内容
-$ git grep "Hello"
-
-# 在某一版本中搜索文本
-$ git grep "Hello" v2.5
-```
-
-### 分支与标签
-
-#### 增删查分支
-
-```bash
-# 列出所有的分支
-$ git branch
-
-# 列出所有的远端分支
-$ git branch -r
-
-# 基于当前分支创建新分支
-$ git branch
-
-# 基于远程分支创建新的可追溯的分支
-$ git branch --track
-
-# 删除本地分支
-$ git branch -d
-
-# 强制删除本地分支,将会丢失未合并的修改
-$ git branch -D
-```
-
-#### 切换分支
-
-```bash
-# 切换分支
-$ git checkout
-
-# 创建并切换到新分支
-$ git checkout -b
-```
-
-#### 标签
-
-```bash
-# 给当前版本打标签
-$ git tag
-
-# 给当前版本打标签并附加消息
-$ git tag -a
-```
-
-### 合并与重置
-
-> merge 与 rebase 虽然是 git 常用功能,但是强烈建议不要使用 git 命令来完成这项工作。
->
-> 因为如果出现代码冲突,在没有代码比对工具的情况下,实在太艰难了。
->
-> 你可以考虑使用各种 Git GUI 工具。
-
-#### 合并
-
-```bash
-# 将分支合并到当前HEAD中
-$ git merge
-```
-
-#### 重置
-
-```bash
-# 将当前HEAD版本重置到分支中,请勿重置已发布的提交
-$ git rebase
-```
-
-### Github
-
-Github 作为最著名的代码开源协作社区,在程序员圈想必无人不知,无人不晓。
-
-这里不赘述 Github 的用法,确实有不会用的新手同学,可以参考官方教程:https://guides.github.com/
-
-#### clone 方式
-
-Git 支持三种协议:HTTPS / SSH / GIT
-
-而 Github 上支持 HTTPS 和 SSH。
-
-HTTPS 这种方式要求你每次 push 时都要输入用户名、密码,有些繁琐。
-
-而 SSH 要求你本地生成证书,然后在你的 Github 账户中注册。第一次配置麻烦是麻烦了点,但是以后就免去了每次 push 需要输入用户名、密码的繁琐。
-
-
-
-以下介绍以下,如何生成证书,以及在 Github 中注册。
-
-#### 生成 SSH 公钥
-
-如前所述,许多 Git 服务器都使用 SSH 公钥进行认证。 为了向 Git 服务器提供 SSH 公钥,如果某系统用户尚未拥有密钥,必须事先为其生成一份。 这个过程在所有操作系统上都是相似的。 首先,你需要确认自己是否已经拥有密钥。 默认情况下,用户的 SSH 密钥存储在其 `\~/.ssh` 目录下。 进入该目录并列出其中内容,你便可以快速确认自己是否已拥有密钥:
-
-```
-$ cd ~/.ssh
-$ ls
-authorized_keys2 id_dsa known_hosts
-config id_dsa.pub
-```
-
-我们需要寻找一对以 `id_dsa` 或 `id_rsa` 命名的文件,其中一个带有 `.pub` 扩展名。 `.pub` 文件是你的公钥,另一个则是私钥。 如果找不到这样的文件(或者根本没有 `.ssh` 目录),你可以通过运行 `ssh-keygen` 程序来创建它们。在 Linux/Mac 系统中,`ssh-keygen` 随 SSH 软件包提供;在 Windows 上,该程序包含于 MSysGit 软件包中。
-
-```
-$ ssh-keygen
-Generating public/private rsa key pair.
-Enter file in which to save the key (/home/schacon/.ssh/id_rsa):
-Created directory '/home/schacon/.ssh'.
-Enter passphrase (empty for no passphrase):
-Enter same passphrase again:
-Your identification has been saved in /home/schacon/.ssh/id_rsa.
-Your public key has been saved in /home/schacon/.ssh/id_rsa.pub.
-The key fingerprint is:
-d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 schacon@mylaptop.local
-```
-
-首先 `ssh-keygen` 会确认密钥的存储位置(默认是 `.ssh/id_rsa`),然后它会要求你输入两次密钥口令。如果你不想在使用密钥时输入口令,将其留空即可。
-
-现在,进行了上述操作的用户需要将各自的公钥发送给任意一个 Git 服务器管理员(假设服务器正在使用基于公钥的 SSH 验证设置)。 他们所要做的就是复制各自的 `.pub` 文件内容,并将其通过邮件发送。 公钥看起来是这样的:
-
-```
-$ cat ~/.ssh/id_rsa.pub
-ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
-GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
-Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
-t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
-mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
-NrRFi9wrf+M7Q== schacon@mylaptop.local
-```
-
-在你的 Github 账户中,依次点击 **Settings** > **SSH and GPG keys** > **New SSH key**
-
-然后,将上面生成的公钥内容粘贴到 `Key` 编辑框并保存。至此大功告成。
-
-后面,你在克隆你的 Github 项目时使用 SSH 方式即可。
-
-
-
-如果觉得我的讲解还不够细致,可以参考:https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/
-
-## 小结
-
-最后,放一张我总结的脑图总结一下以上的知识点。
-
-
-
-## 资料
-
-[git 官网](https://git-scm.com/) | [git 官方 Github](https://github.com/git/git)
-
-[廖雪峰的 git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
-
-[git-cheat-sheet](https://github.com/arslanbilal/git-cheat-sheet)
-
-[github-cheat-sheet](https://github.com/tiimgreen/github-cheat-sheet)
-
-[Github gitignore 模板](https://github.com/github/gitignore)
diff --git a/docs/git/github-git-cheat-sheet.pdf b/docs/git/github-git-cheat-sheet.pdf
deleted file mode 100644
index 64ddc419..00000000
Binary files a/docs/git/github-git-cheat-sheet.pdf and /dev/null differ
diff --git a/docs/index.html b/docs/index.html
deleted file mode 100644
index b72a9db2..00000000
--- a/docs/index.html
+++ /dev/null
@@ -1,245 +0,0 @@
-
-
-
-
- Linux Tutorial
-
-
-
-
-
-
-
-
-
-
-
- 正在加载...
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/kubernetes/kubernetes.md b/docs/kubernetes/kubernetes.md
deleted file mode 100644
index fdee32f1..00000000
--- a/docs/kubernetes/kubernetes.md
+++ /dev/null
@@ -1,176 +0,0 @@
-# Kubernetes
-
-> Kubernetes 是用于自动部署,扩展和管理 Docker 应用程序的开源系统。简称 K8S
->
-> 关键词: `docker`
-
-
-
-- [功能](#功能)
-- [简介](#简介)
-- [基础](#基础)
-- [进阶](#进阶)
-- [命令](#命令)
-- [引用和引申](#引用和引申)
-
-
-
-## 功能
-
-- 基于容器的应用部署、维护和滚动升级
-- 负载均衡和服务发现
-- 跨机器和跨地区的集群调度
-- 自动伸缩
-- 无状态服务和有状态服务
-- 广泛的 Volume 支持
-- 插件机制保证扩展性
-
-## 简介
-
-Kubernetes 主控组件(Master) 包含三个进程,都运行在集群中的某个节上,通常这个节点被称为 master 节点。这些进程包括:`kube-apiserver`、`kube-controller-manager` 和 `kube-scheduler`。
-
-集群中的每个非 master 节点都运行两个进程:
-
-- kubelet,和 master 节点进行通信。
-- kube-proxy,一种网络代理,将 Kubernetes 的网络服务代理到每个节点上。
-
-### Kubernetes 对象
-
-Kubernetes 包含若干抽象用来表示系统状态,包括:已部署的容器化应用和负载、与它们相关的网络和磁盘资源以及有关集群正在运行的其他操作的信息。
-
-
-- Pod - kubernetes 对象模型中最小的单元,它代表集群中一个正在运行的进程。
-- Service
-- Volume
-- Namespace
-
-
-
-高级对象
-
-- ReplicaSet
-- Deployment
-- StatefulSet
-- DaemonSet
-- Job
-
-## 基础
-
-## 进阶
-
-## 命令
-
-### 客户端配置
-
-```bash
-# Setup autocomplete in bash; bash-completion package should be installed first
-source <(kubectl completion bash)
-
-# View Kubernetes config
-kubectl config view
-
-# View specific config items by json path
-kubectl config view -o jsonpath='{.users[?(@.name == "k8s")].user.password}'
-
-# Set credentials for foo.kuberntes.com
-kubectl config set-credentials kubeuser/foo.kubernetes.com --username=kubeuser --password=kubepassword
-```
-
-### 查找资源
-
-```bash
-# List all services in the namespace
-kubectl get services
-
-# List all pods in all namespaces in wide format
-kubectl get pods -o wide --all-namespaces
-
-# List all pods in json (or yaml) format
-kubectl get pods -o json
-
-# Describe resource details (node, pod, svc)
-kubectl describe nodes my-node
-
-# List services sorted by name
-kubectl get services --sort-by=.metadata.name
-
-# List pods sorted by restart count
-kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'
-
-# Rolling update pods for frontend-v1
-kubectl rolling-update frontend-v1 -f frontend-v2.json
-
-# Scale a replicaset named 'foo' to 3
-kubectl scale --replicas=3 rs/foo
-
-# Scale a resource specified in "foo.yaml" to 3
-kubectl scale --replicas=3 -f foo.yaml
-
-# Execute a command in every pod / replica
-for i in 0 1; do kubectl exec foo-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done
-```
-
-### 资源管理
-
-```bash
-# Get documentation for pod or service
-kubectl explain pods,svc
-
-# Create resource(s) like pods, services or daemonsets
-kubectl create -f ./my-manifest.yaml
-
-# Apply a configuration to a resource
-kubectl apply -f ./my-manifest.yaml
-
-# Start a single instance of Nginx
-kubectl run nginx --image=nginx
-
-# Create a secret with several keys
-cat < 学习 Linux 的第一步:当然是从 Linux 命令入手了。
-> 根据应用场景,将常见 Linux 命令分门别类的一一介绍。
->
-> 如果想快速学习,推荐参考这篇文章:[命令行的艺术(转载)](命令行的艺术.md)
+## 📖 内容
-- [查看 Linux 命令帮助信息](查看Linux命令帮助信息.md) - 关键词:`help`, `whatis`, `info`, `which`, `whereis`, `man`
-- [Linux 文件目录管理](Linux文件目录管理.md) - 关键词:`cd`, `ls`, `pwd`, `mkdir`, `rmdir`, `tree`, `touch`, `ln`, `rename`, `stat`, `file`, `chmod`, `chown`, `locate`, `find`, `cp`, `mv`, `rm`
-- [Linux 文件内容查看命令](Linux文件内容查看编辑.md) - 关键词:`cat`, `head`, `tail`, `more`, `less`, `sed`, `vi`, `grep`
-- [Linux 文件压缩和解压](Linux文件压缩和解压.md) - 关键词:`tar`, `gzip`, `zip`, `unzip`
-- [Linux 用户管理](Linux用户管理.md) - 关键词:`groupadd`, `groupdel`, `groupmod`, `useradd`, `userdel`, `usermod`, `passwd`, `su`, `sudo`
-- [Linux 系统管理](Linux系统管理.md) - 关键词:`reboot`, `exit`, `shutdown`, `date`, `mount`, `umount`, `ps`, `kill`, `systemctl`, `service`, `crontab`
-- [Linux 网络管理](Linux网络管理.md) - 关键词:关键词:`curl`, `wget`, `telnet`, `ip`, `hostname`, `ifconfig`, `route`, `ssh`, `ssh-keygen`, `firewalld`, `iptables`, `host`, `nslookup`, `nc`/`netcat`, `ping`, `traceroute`, `netstat`
-- [Linux 硬件管理](Linux硬件管理.md) - 关键词:`df`, `du`, `top`, `free`, `iotop`
-- [Linux 软件管理](Linux硬件管理.md) - 关键词:`rpm`, `yum`, `apt-get`
+- [查看 Linux 命令帮助信息](linux-cli-help.md) - 关键词:`help`, `whatis`, `info`, `which`, `whereis`, `man`
+- [Linux 文件目录管理](linux-cli-dir.md) - 关键词:`cd`, `ls`, `pwd`, `mkdir`, `rmdir`, `tree`, `touch`, `ln`, `rename`, `stat`, `file`, `chmod`, `chown`, `locate`, `find`, `cp`, `mv`, `rm`
+- [Linux 文件内容查看命令](linux-cli-file.md) - 关键词:`cat`, `head`, `tail`, `more`, `less`, `sed`, `vi`, `grep`
+- [Linux 文件压缩和解压](linux-cli-file-compress.md) - 关键词:`tar`, `gzip`, `zip`, `unzip`
+- [Linux 用户管理](linux-cli-user.md) - 关键词:`groupadd`, `groupdel`, `groupmod`, `useradd`, `userdel`, `usermod`, `passwd`, `su`, `sudo`
+- [Linux 系统管理](linux-cli-system.md) - 关键词:`reboot`, `exit`, `shutdown`, `date`, `mount`, `umount`, `ps`, `kill`, `systemctl`, `service`, `crontab`
+- [Linux 网络管理](linux-cli-net.md) - 关键词:关键词:`curl`, `wget`, `telnet`, `ip`, `hostname`, `ifconfig`, `route`, `ssh`, `ssh-keygen`, `firewalld`, `iptables`, `host`, `nslookup`, `nc`/`netcat`, `ping`, `traceroute`, `netstat`
+- [Linux 硬件管理](linux-cli-hardware.md) - 关键词:`df`, `du`, `top`, `free`, `iotop`
+- [Linux 软件管理](linux-cli-software.md) - 关键词:`rpm`, `yum`, `apt-get`
+
+## 📚 资料
+
+- [命令行的艺术](https://github.com/jlevy/the-art-of-command-line/blob/master/README-zh.md)
+- [Linux命令大全](https://man.linuxde.net/)
+- [linux-command](https://github.com/jaywcjlove/linux-command)
+
+## 🚪 传送门
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾ 🎯 [钝悟的博客](https://dunwu.github.io/blog/) ◾
diff --git a/docs/linux/cli/free.md b/docs/linux/cli/free.md
new file mode 100644
index 00000000..385ea0e4
--- /dev/null
+++ b/docs/linux/cli/free.md
@@ -0,0 +1,155 @@
+# free
+
+显示内存的使用情况
+
+## 补充说明
+
+**free 命令** 可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区。
+
+### 语法
+
+```shell
+free(选项)
+```
+
+### 选项
+
+```shell
+-b # 以Byte为单位显示内存使用情况;
+-k # 以KB为单位显示内存使用情况;
+-m # 以MB为单位显示内存使用情况;
+-g # 以GB为单位显示内存使用情况。
+-o # 不显示缓冲区调节列;
+-s<间隔秒数> # 持续观察内存使用状况;
+-t # 显示内存总和列;
+-V # 显示版本信息。
+```
+
+### 实例
+
+```shell
+free -t # 以总和的形式显示内存的使用信息
+free -s 10 # 周期性的查询内存使用信息,每10s 执行一次命令
+```
+
+显示内存使用情况
+
+```shell
+free -m
+ total used free shared buffers cached
+Mem: 2016 1973 42 0 163 1497
+-/+ buffers/cache: 312 1703
+Swap: 4094 0 4094
+```
+
+**第一部分 Mem 行解释:**
+
+```shell
+total:内存总数;
+used:已经使用的内存数;
+free:空闲的内存数;
+shared:当前已经废弃不用;
+buffers Buffer:缓存内存数;
+cached Page:缓存内存数。
+```
+
+关系:total = used + free
+
+**第二部分(-/+ buffers/cache)解释:**
+
+```shell
+(-buffers/cache) used内存数:第一部分Mem行中的 used – buffers – cached
+(+buffers/cache) free内存数: 第一部分Mem行中的 free + buffers + cached
+```
+
+可见-buffers/cache 反映的是被程序实实在在吃掉的内存,而+buffers/cache 反映的是可以挪用的内存总数。
+
+第三部分是指交换分区。
+
+输出结果的第四行是交换分区 SWAP 的,也就是我们通常所说的虚拟内存。
+区别:第二行(mem)的 used/free 与第三行(-/+ buffers/cache) used/free 的区别。 这两个的区别在于使用的角度来看,第一行是从 OS 的角度来看,因为对于 OS,buffers/cached 都是属于被使用,所以他的可用内存是 2098428KB,已用内存是 30841684KB,其中包括,内核(OS)使用+Application(X, oracle,etc)使用的+buffers+cached.
+
+第三行所指的是从应用程序角度来看,对于应用程序来说,buffers/cached 是等于可用的,因为 buffer/cached 是为了提高文件读取的性能,当应用程序需在用到内存的时候,buffer/cached 会很快地被回收。
+
+所以从应用程序的角度来说,可用内存=系统 free memory+buffers+cached。
+如本机情况的可用内存为:
+
+18007156=2098428KB+4545340KB+11363424KB
+
+接下来解释什么时候内存会被交换,以及按什么方交换。
+
+当可用内存少于额定值的时候,就会开会进行交换。如何看额定值:
+
+```shell
+cat /proc/meminfo
+
+MemTotal: 16140816 kB
+MemFree: 816004 kB
+MemAvailable: 2913824 kB
+Buffers: 17912 kB
+Cached: 2239076 kB
+SwapCached: 0 kB
+Active: 12774804 kB
+Inactive: 1594328 kB
+Active(anon): 12085544 kB
+Inactive(anon): 94572 kB
+Active(file): 689260 kB
+Inactive(file): 1499756 kB
+Unevictable: 116888 kB
+Mlocked: 116888 kB
+SwapTotal: 8191996 kB
+SwapFree: 8191996 kB
+Dirty: 56 kB
+Writeback: 0 kB
+AnonPages: 12229228 kB
+Mapped: 117136 kB
+Shmem: 58736 kB
+Slab: 395568 kB
+SReclaimable: 246700 kB
+SUnreclaim: 148868 kB
+KernelStack: 30496 kB
+PageTables: 165104 kB
+NFS_Unstable: 0 kB
+Bounce: 0 kB
+WritebackTmp: 0 kB
+CommitLimit: 16262404 kB
+Committed_AS: 27698600 kB
+VmallocTotal: 34359738367 kB
+VmallocUsed: 311072 kB
+VmallocChunk: 34350899200 kB
+HardwareCorrupted: 0 kB
+AnonHugePages: 3104768 kB
+HugePages_Total: 0
+HugePages_Free: 0
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+Hugepagesize: 2048 kB
+DirectMap4k: 225536 kB
+DirectMap2M: 13279232 kB
+DirectMap1G: 5242880 kB
+```
+
+交换将通过三个途径来减少系统中使用的物理页面的个数:
+
+1. 减少缓冲与页面 cache 的大小,
+2. 将系统 V 类型的内存页面交换出去,
+3. 换出或者丢弃页面。(Application 占用的内存页,也就是物理内存不足)。
+
+事实上,少量地使用 swap 是不是影响到系统性能的。
+
+那 buffers 和 cached 都是缓存,两者有什么区别呢?
+
+为了提高磁盘存取效率, Linux 做了一些精心的设计, 除了对 dentry 进行缓存(用于 VFS,加速文件路径名到 inode 的转换), 还采取了两种主要 Cache 方式:
+
+Buffer Cache 和 Page Cache。前者针对磁盘块的读写,后者针对文件 inode 的读写。这些 Cache 有效缩短了 I/O 系统调用(比如 read,write,getdents)的时间。
+磁盘的操作有逻辑级(文件系统)和物理级(磁盘块),这两种 Cache 就是分别缓存逻辑和物理级数据的。
+
+Page cache 实际上是针对文件系统的,是文件的缓存,在文件层面上的数据会缓存到 page cache。文件的逻辑层需要映射到实际的物理磁盘,这种映射关系由文件系统来完成。当 page cache 的数据需要刷新时,page cache 中的数据交给 buffer cache,因为 Buffer Cache 就是缓存磁盘块的。但是这种处理在 2.6 版本的内核之后就变的很简单了,没有真正意义上的 cache 操作。
+
+Buffer cache 是针对磁盘块的缓存,也就是在没有文件系统的情况下,直接对磁盘进行操作的数据会缓存到 buffer cache 中,例如,文件系统的元数据都会缓存到 buffer cache 中。
+
+简单说来,page cache 用来缓存文件数据,buffer cache 用来缓存磁盘数据。在有文件系统的情况下,对文件操作,那么数据会缓存到 page cache,如果直接采用 dd 等工具对磁盘进行读写,那么数据会缓存到 buffer cache。
+
+所以我们看 linux,只要不用 swap 的交换空间,就不用担心自己的内存太少.如果常常 swap 用很多,可能你就要考虑加物理内存了.这也是 linux 看内存是否够用的标准.
+
+如果是应用服务器的话,一般只看第二行,+buffers/cache,即对应用程序来说 free 的内存太少了,也是该考虑优化程序或加内存了。
diff --git a/docs/linux/cli/grep.md b/docs/linux/cli/grep.md
new file mode 100644
index 00000000..37508fdc
--- /dev/null
+++ b/docs/linux/cli/grep.md
@@ -0,0 +1,245 @@
+# grep
+
+强大的文本搜索工具
+
+## 补充说明
+
+**grep** (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。用于过滤/搜索的特定字符。可使用正则表达式能多种命令配合使用,使用上十分灵活。
+
+### 选项
+
+```shell
+-a --text # 不要忽略二进制数据。
+-A <显示行数> --after-context=<显示行数> # 除了显示符合范本样式的那一行之外,并显示该行之后的内容。
+-b --byte-offset # 在显示符合范本样式的那一行之外,并显示该行之前的内容。
+-B<显示行数> --before-context=<显示行数> # 除了显示符合样式的那一行之外,并显示该行之前的内容。
+-c --count # 计算符合范本样式的列数。
+-C<显示行数> --context=<显示行数>或-<显示行数> # 除了显示符合范本样式的那一列之外,并显示该列之前后的内容。
+-d<进行动作> --directories=<动作> # 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep命令将回报信息并停止动作。
+-e<范本样式> --regexp=<范本样式> # 指定字符串作为查找文件内容的范本样式。
+-E --extended-regexp # 将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式。
+-f<范本文件> --file=<规则文件> # 指定范本文件,其内容有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每一列的范本样式。
+-F --fixed-regexp # 将范本样式视为固定字符串的列表。
+-G --basic-regexp # 将范本样式视为普通的表示法来使用。
+-h --no-filename # 在显示符合范本样式的那一列之前,不标示该列所属的文件名称。
+-H --with-filename # 在显示符合范本样式的那一列之前,标示该列的文件名称。
+-i --ignore-case # 忽略字符大小写的差别。
+-l --file-with-matches # 列出文件内容符合指定的范本样式的文件名称。
+-L --files-without-match # 列出文件内容不符合指定的范本样式的文件名称。
+-n --line-number # 在显示符合范本样式的那一列之前,标示出该列的编号。
+-P --perl-regexp # PATTERN 是一个 Perl 正则表达式
+-q --quiet或--silent # 不显示任何信息。
+-R/-r --recursive # 此参数的效果和指定“-d recurse”参数相同。
+-s --no-messages # 不显示错误信息。
+-v --revert-match # 反转查找。
+-V --version # 显示版本信息。
+-w --word-regexp # 只显示全字符合的列。
+-x --line-regexp # 只显示全列符合的列。
+-y # 此参数效果跟“-i”相同。
+-o # 只输出文件中匹配到的部分。
+-m --max-count= # 找到num行结果后停止查找,用来限制匹配行数
+```
+
+### 规则表达式
+
+```shell
+^ # 锚定行的开始 如:'^grep'匹配所有以grep开头的行。
+$ # 锚定行的结束 如:'grep$' 匹配所有以grep结尾的行。
+. # 匹配一个非换行符的字符 如:'gr.p'匹配gr后接一个任意字符,然后是p。
+* # 匹配零个或多个先前字符 如:'*grep'匹配所有一个或多个空格后紧跟grep的行。
+.* # 一起用代表任意字符。
+[] # 匹配一个指定范围内的字符,如'[Gg]rep'匹配Grep和grep。
+[^] # 匹配一个不在指定范围内的字符,如:'[^A-FH-Z]rep'匹配不包含A-R和T-Z的一个字母开头,紧跟rep的行。
+\(..\) # 标记匹配字符,如'\(love\)',love被标记为1。
+\< # 锚定单词的开始,如:'\ # 锚定单词的结束,如'grep\>'匹配包含以grep结尾的单词的行。
+x\{m\} # 重复字符x,m次,如:'0\{5\}'匹配包含5个o的行。
+x\{m,\} # 重复字符x,至少m次,如:'o\{5,\}'匹配至少有5个o的行。
+x\{m,n\} # 重复字符x,至少m次,不多于n次,如:'o\{5,10\}'匹配5--10个o的行。
+\w # 匹配文字和数字字符,也就是[A-Za-z0-9],如:'G\w*p'匹配以G后跟零个或多个文字或数字字符,然后是p。
+\W # \w的反置形式,匹配一个或多个非单词字符,如点号句号等。
+\b # 单词锁定符,如: '\bgrep\b'只匹配grep。
+```
+
+## grep 命令常见用法
+
+在文件中搜索一个单词,命令会返回一个包含 **“match_pattern”** 的文本行:
+
+```shell
+grep match_pattern file_name
+grep "match_pattern" file_name
+```
+
+在多个文件中查找:
+
+```shell
+grep "match_pattern" file_1 file_2 file_3 ...
+```
+
+输出除之外的所有行 **-v** 选项:
+
+```shell
+grep -v "match_pattern" file_name
+```
+
+标记匹配颜色 **--color=auto** 选项:
+
+```shell
+grep "match_pattern" file_name --color=auto
+```
+
+使用正则表达式 **-E** 选项:
+
+```shell
+grep -E "[1-9]+"
+# 或
+egrep "[1-9]+"
+```
+
+使用正则表达式 **-P** 选项:
+
+```shell
+grep -P "(\d{3}\-){2}\d{4}" file_name
+```
+
+只输出文件中匹配到的部分 **-o** 选项:
+
+```shell
+echo this is a test line. | grep -o -E "[a-z]+\."
+line.
+
+echo this is a test line. | egrep -o "[a-z]+\."
+line.
+```
+
+统计文件或者文本中包含匹配字符串的行数 **-c** 选项:
+
+```shell
+grep -c "text" file_name
+```
+
+输出包含匹配字符串的行数 **-n** 选项:
+
+```shell
+grep "text" -n file_name
+# 或
+cat file_name | grep "text" -n
+
+#多个文件
+grep "text" -n file_1 file_2
+```
+
+打印样式匹配所位于的字符或字节偏移:
+
+```shell
+echo gun is not unix | grep -b -o "not"
+7:not
+#一行中字符串的字符便宜是从该行的第一个字符开始计算,起始值为0。选项 **-b -o** 一般总是配合使用。
+```
+
+搜索多个文件并查找匹配文本在哪些文件中:
+
+```shell
+grep -l "text" file1 file2 file3...
+```
+
+### grep 递归搜索文件
+
+在多级目录中对文本进行递归搜索:
+
+```shell
+grep "text" . -r -n
+# .表示当前目录。
+```
+
+忽略匹配样式中的字符大小写:
+
+```shell
+echo "hello world" | grep -i "HELLO"
+# hello
+```
+
+选项 **-e** 制动多个匹配样式:
+
+```shell
+echo this is a text line | grep -e "is" -e "line" -o
+is
+line
+
+#也可以使用 **-f** 选项来匹配多个样式,在样式文件中逐行写出需要匹配的字符。
+cat patfile
+aaa
+bbb
+
+echo aaa bbb ccc ddd eee | grep -f patfile -o
+```
+
+在 grep 搜索结果中包括或者排除指定文件:
+
+```shell
+# 只在目录中所有的.php和.html文件中递归搜索字符"main()"
+grep "main()" . -r --include *.{php,html}
+
+# 在搜索结果中排除所有README文件
+grep "main()" . -r --exclude "README"
+
+# 在搜索结果中排除filelist文件列表里的文件
+grep "main()" . -r --exclude-from filelist
+
+```
+
+使用 0 值字节后缀的 grep 与 xargs:
+
+```shell
+# 测试文件:
+echo "aaa" > file1
+echo "bbb" > file2
+echo "aaa" > file3
+
+grep "aaa" file* -lZ | xargs -0 rm
+
+# 执行后会删除file1和file3,grep输出用-Z选项来指定以0值字节作为终结符文件名(\0),xargs -0 读取输入并用0值字节终结符分隔文件名,然后删除匹配文件,-Z通常和-l结合使用。
+```
+
+grep 静默输出:
+
+```shell
+grep -q "test" filename
+# 不会输出任何信息,如果命令运行成功返回0,失败则返回非0值。一般用于条件测试。
+```
+
+打印出匹配文本之前或者之后的行:
+
+```shell
+# 显示匹配某个结果之后的3行,使用 -A 选项:
+seq 10 | grep "5" -A 3
+5
+6
+7
+8
+
+# 显示匹配某个结果之前的3行,使用 -B 选项:
+seq 10 | grep "5" -B 3
+2
+3
+4
+5
+
+# 显示匹配某个结果的前三行和后三行,使用 -C 选项:
+seq 10 | grep "5" -C 3
+2
+3
+4
+5
+6
+7
+8
+
+# 如果匹配结果有多个,会用“--”作为各匹配结果之间的分隔符:
+echo -e "a\nb\nc\na\nb\nc" | grep a -A 1
+a
+b
+--
+a
+b
+```
diff --git a/docs/linux/cli/iostat.md b/docs/linux/cli/iostat.md
new file mode 100644
index 00000000..c4fce1ea
--- /dev/null
+++ b/docs/linux/cli/iostat.md
@@ -0,0 +1,70 @@
+# iostat
+
+监视系统输入输出设备和 CPU 的使用情况
+
+## 补充说明
+
+**iostat 命令** 被用于监视系统输入输出设备和 CPU 的使用情况。它的特点是汇报磁盘活动统计情况,同时也会汇报出 CPU 使用情况。同 vmstat 一样,iostat 也有一个弱点,就是它不能对某个进程进行深入分析,仅对系统的整体情况进行分析。
+
+### 语法
+
+```shell
+iostat(选项)(参数)
+```
+
+### 选项
+
+```shell
+-c:仅显示CPU使用情况;
+-d:仅显示设备利用率;
+-k:显示状态以千字节每秒为单位,而不使用块每秒;
+-m:显示状态以兆字节每秒为单位;
+-p:仅显示块设备和所有被使用的其他分区的状态;
+-t:显示每个报告产生时的时间;
+-V:显示版号并退出;
+-x:显示扩展状态。
+```
+
+### 参数
+
+- 间隔时间:每次报告的间隔时间(秒);
+- 次数:显示报告的次数。
+
+### 实例
+
+用`iostat -x /dev/sda1`来观看磁盘 I/O 的详细情况:
+
+```shell
+iostat -x /dev/sda1
+Linux 2.6.18-164.el5xen (localhost.localdomain)
+2010年03月26日
+
+avg-cpu: %user %nice %system %iowait
+%steal %idle
+ 0.11 0.02 0.18 0.35
+0.03 99.31
+
+Device: tps Blk_read/s Blk_wrtn/s
+Blk_read Blk_wrtn
+sda1 0.02 0.08
+0.00 2014 4
+```
+
+详细说明:第二行是系统信息和监测时间,第三行和第四行显示 CPU 使用情况(具体内容和 mpstat 命令相同)。这里主要关注后面 I/O 输出的信息,如下所示:
+
+| 标示 | 说明 |
+| -------- | ----------------------------------- |
+| Device | 监测设备名称 |
+| rrqm/s | 每秒需要读取需求的数量 |
+| wrqm/s | 每秒需要写入需求的数量 |
+| r/s | 每秒实际读取需求的数量 |
+| w/s | 每秒实际写入需求的数量 |
+| rsec/s | 每秒读取区段的数量 |
+| wsec/s | 每秒写入区段的数量 |
+| rkB/s | 每秒实际读取的大小,单位为 KB |
+| wkB/s | 每秒实际写入的大小,单位为 KB |
+| avgrq-sz | 需求的平均大小区段 |
+| avgqu-sz | 需求的平均队列长度 |
+| await | 等待 I/O 平均的时间(milliseconds) |
+| svctm | I/O 需求完成的平均时间 |
+| %util | 被 I/O 需求消耗的 CPU 百分比 |
diff --git a/docs/linux/cli/iotop.md b/docs/linux/cli/iotop.md
new file mode 100644
index 00000000..42dd7354
--- /dev/null
+++ b/docs/linux/cli/iotop.md
@@ -0,0 +1,79 @@
+# iotop
+
+用来监视磁盘 I/O 使用状况的工具
+
+## 补充说明
+
+**iotop 命令** 是一个用来监视磁盘 I/O 使用状况的 top 类工具。iotop 具有与 top 相似的 UI,其中包括 PID、用户、I/O、进程等相关信息。Linux 下的 IO 统计工具如 iostat,nmon 等大多数是只能统计到 per 设备的读写情况,如果你想知道每个进程是如何使用 IO 的就比较麻烦,使用 iotop 命令可以很方便的查看。
+
+iotop 使用 Python 语言编写而成,要求 Python2.5(及以上版本)和 Linux kernel2.6.20(及以上版本)。iotop 提供有源代码及 rpm 包,可从其官方主页下载。
+
+### 安装
+
+**Ubuntu**
+
+```shell
+apt-get install iotop
+```
+
+**CentOS**
+
+```shell
+yum install iotop
+```
+
+**编译安装**
+
+```shell
+wget http://guichaz.free.fr/iotop/files/iotop-0.4.4.tar.gz
+tar zxf iotop-0.4.4.tar.gz
+python setup.py build
+python setup.py install
+```
+
+### 语法
+
+```shell
+iotop(选项)
+```
+
+### 选项
+
+```shell
+-o:只显示有io操作的进程
+-b:批量显示,无交互,主要用作记录到文件。
+-n NUM:显示NUM次,主要用于非交互式模式。
+-d SEC:间隔SEC秒显示一次。
+-p PID:监控的进程pid。
+-u USER:监控的进程用户。
+```
+
+**iotop 常用快捷键:**
+
+1. 左右箭头:改变排序方式,默认是按 IO 排序。
+2. r:改变排序顺序。
+3. o:只显示有 IO 输出的进程。
+4. p:进程/线程的显示方式的切换。
+5. a:显示累积使用量。
+6. q:退出。
+
+### 实例
+
+直接执行 iotop 就可以看到效果了:
+
+```shell
+Total DISK read: 0.00 B/s | Total DISK write: 0.00 B/s
+ TID PRIO USER DISK READ DISK WRITE SWAPIN IO> command
+ 1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init [3]
+ 2 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kthreadd]
+ 3 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [migration/0]
+ 4 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [ksoftirqd/0]
+ 5 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [watchdog/0]
+ 6 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [migration/1]
+ 7 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [ksoftirqd/1]
+ 8 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [watchdog/1]
+ 9 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [events/0]
+ 10 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [events/1]
+ 11 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [khelper]
+2572 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [bluetooth]
+```
diff --git "a/docs/linux/cli/Linux\346\226\207\344\273\266\347\233\256\345\275\225\347\256\241\347\220\206.md" b/docs/linux/cli/linux-cli-dir.md
similarity index 89%
rename from "docs/linux/cli/Linux\346\226\207\344\273\266\347\233\256\345\275\225\347\256\241\347\220\206.md"
rename to docs/linux/cli/linux-cli-dir.md
index d2899e11..16f82d4a 100644
--- "a/docs/linux/cli/Linux\346\226\207\344\273\266\347\233\256\345\275\225\347\256\241\347\220\206.md"
+++ b/docs/linux/cli/linux-cli-dir.md
@@ -1,58 +1,16 @@
----
-title: Linux 文件目录管理命令
-date: 2018-02-27
-categories:
- - linux
-tags:
- - linux
- - command
----
-
# Linux 文件目录管理
> 关键词:`cd`, `ls`, `pwd`, `mkdir`, `rmdir`, `tree`, `touch`, `ln`, `rename`, `stat`, `file`, `chmod`, `chown`, `locate`, `find`, `cp`, `scp`, `mv`, `rm`
-
-
-- [Linux 文件目录工作机制](#linux-文件目录工作机制)
- - [Linux 目录结构](#linux-目录结构)
- - [Linux 文件属性](#linux-文件属性)
-- [Linux 文件目录管理要点](#linux-文件目录管理要点)
- - [目录管理](#目录管理)
- - [文件管理](#文件管理)
- - [文件和目录通用管理](#文件和目录通用管理)
-- [命令常见用法](#命令常见用法)
- - [cd](#cd)
- - [ls](#ls)
- - [pwd](#pwd)
- - [mkdir](#mkdir)
- - [rmdir](#rmdir)
- - [tree](#tree)
- - [touch](#touch)
- - [ln](#ln)
- - [rename](#rename)
- - [stat](#stat)
- - [file](#file)
- - [chmod](#chmod)
- - [chown](#chown)
- - [locate](#locate)
- - [find](#find)
- - [cp](#cp)
- - [scp](#scp)
- - [mv](#mv)
- - [rm](#rm)
-
-
-
-## Linux 文件目录工作机制
-
-### Linux 目录结构
+## 1. Linux 文件目录工作机制
+
+### 1.1. Linux 目录结构
linux 目录结构是树形结构,其根目录是 `/` 。一张思维导图说明各个目录的作用:
-
+
-### Linux 文件属性
+### 1.2. Linux 文件属性
Linux 系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。为了保护系统的安全性,Linux 系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定。
在 Linux 中我们可以使用 ll 或者 ls –l 命令来显示一个文件的属性以及文件所属的用户和组,如:
@@ -60,7 +18,7 @@ Linux 系统是一种典型的多用户系统,不同的用户处于不同的
```bash
$ ls -l
total 64
-dr-xr-xr-x 2 root root 4096 Dec 14 2012 bin
+drwxr-xr-x 2 root root 4096 Dec 14 2012 bin
dr-xr-xr-x 4 root root 4096 Apr 19 2012 boot
```
@@ -77,7 +35,7 @@ dr-xr-xr-x 4 root root 4096 Apr 19 2012 boot
每个文件的属性由左边第一部分的 10 个字符来确定(如下图)。
-
+
从左至右用 0-9 这些数字来表示。
@@ -89,12 +47,27 @@ dr-xr-xr-x 4 root root 4096 Apr 19 2012 boot
- 第 2、5、8 位表示写权限,如果用"w"字符表示,则有写权限,如果用"-"字符表示没有写权限。
- 第 3、6、9 位表示可执行权限,如果用"x"字符表示,则有执行权限,如果用"-"字符表示,则没有执行权限。
-#### Linux 文件属主和属组
+```bash
+d rwx r-x r-x
+↑ ↑↑↑ ↑↑↑ ↑↑↑
+│ │││ │││ │││-其他用户执行权限 (x/-)
+│ │││ │││ │└─ 其他用户写权限 (w/-)
+│ │││ │││ └── 其他用户读权限 (r/-)
+│ │││ ││└──── 属组用户执行权限 (x/-)
+│ │││ │└───── 属组用户写权限 (w/-)
+│ │││ └────── 属组用户读权限 (r/-)
+│ ││└──────── 属主用户执行权限 (x/-)
+│ │└───────── 属主用户写权限 (w/-)
+│ └────────── 属主用户读权限 (r/-)
+└──────────── 文件类型 (该文件是目录)
+```
+
+#### 1.2.1. Linux 文件属主和属组
```bash
$ ls -l
total 64
-dr-xr-xr-x 2 root root 4096 Dec 14 2012 bin
+drwxr-xr-x 2 root root 4096 Dec 14 2012 bin
dr-xr-xr-x 4 root root 4096 Apr 19 2012 boot
```
@@ -104,9 +77,9 @@ dr-xr-xr-x 4 root root 4096 Apr 19 2012 boot
- 因此,Linux 系统按文件拥有者、文件拥有者同组用户和其他用户来规定了不同的文件访问权限。
- 在以上实例中,bin 文件是一个目录文件,属主和属组都为 root,属主有可读、可写、可执行的权限;与属主同组的其他用户有可读和可执行的权限;其他用户也有可读和可执行的权限。
-## Linux 文件目录管理要点
+## 2. Linux 文件目录管理要点
-### 目录管理
+### 2.1. 目录管理
- 切换目录 - 使用 [cd](#cd)
- 查看目录信息 - 使用 [ls](#ls)
@@ -115,7 +88,7 @@ dr-xr-xr-x 4 root root 4096 Apr 19 2012 boot
- 创建目录 - 使用 [mkdir](#mkdir)
- 删除目录 - 使用 [rmdir](#rmdir)
-### 文件管理
+### 2.2. 文件管理
- 创建空文件 - 使用 [touch](#touch)
- 为文件创建连接 - 使用 [ln](#ln)
@@ -129,16 +102,16 @@ dr-xr-xr-x 4 root root 4096 Apr 19 2012 boot
- 查找命令的绝对路径 - 使用 [which](#which)
- 查找命令的程序、源代码等相关文件 - 使用 [whereis](#whereis)
-### 文件和目录通用管理
+### 2.3. 文件和目录通用管理
- 复制文件或目录 - 使用 [cp](#cp)
- 复制文件或目录到远程服务器 - 使用 [scp](#scp)
- 移动文件或目录 - 使用 [mv](#mv)
- 删除文件或目录 - 使用 [rm](#rm)
-## 命令常见用法
+## 3. 命令常见用法
-### cd
+### 3.1. cd
> cd 命令用来切换工作目录。
>
@@ -154,7 +127,7 @@ cd .. # 切换到上级目录
cd ../.. # 切换到上两级目录
```
-### ls
+### 3.2. ls
> ls 命令用来显示目录信息。
>
@@ -172,13 +145,13 @@ ls -ltr # 按修改时间列出文件和文件夹详细信息
ls --color=auto # 列出文件并标记颜色分类
```
-### pwd
+### 3.3. pwd
> pwd 命令用来显示当前目录的绝对路径。
>
> 参考:http://man.linuxde.net/pwd
-### mkdir
+### 3.4. mkdir
> mkdir 命令用来创建目录。
>
@@ -194,7 +167,7 @@ mkdir -p zp/test
mkdir -p -m 750 zp/test
```
-### rmdir
+### 3.5. rmdir
> rmdir 命令用来删除空目录。
>
@@ -207,7 +180,7 @@ mkdir -p -m 750 zp/test
rmdir -p zp/test
```
-### tree
+### 3.6. tree
> tree 命令以树状显示目录的内。
>
@@ -234,7 +207,7 @@ tree -L 2 > /home/www/tree.txt # 当前目录结果存到 tree.txt 文件中
tree -I 'node_modules|icon|font' -L 2
```
-### touch
+### 3.7. touch
> touch 命令有两个功能:一是用于把已存在文件的时间标签更新为系统当前的时间(默认方式),它们的数据将原封不动地保留下来;二是用来创建空文件。
>
@@ -246,11 +219,11 @@ tree -I 'node_modules|icon|font' -L 2
touch ex2
```
-### ln
+### 3.8. ln
> ln 命令用来为文件创建连接,连接类型分为硬连接和符号连接两种,默认的连接类型是硬连接。如果要创建符号连接必须使用"-s"选项。
>
-> 注意:符号链接文件不是一个独立的文件,它的许多属性依赖于源文件,所以给符号链接文件设置存取权限是没有意义的。
+> 🔔 注意:符号链接文件不是一个独立的文件,它的许多属性依赖于源文件,所以给符号链接文件设置存取权限是没有意义的。
>
> 参考:http://man.linuxde.net/ln
@@ -266,7 +239,7 @@ ln /mub1/m2.c /usr/liu/a2.c
ln -s /usr/mengqc/mub1 /usr/liu/abc
```
-### rename
+### 3.9. rename
> rename 命令用字符串替换的方式批量重命名。
>
@@ -284,7 +257,7 @@ rename "s/$//.txt/" * # 把所有的文件名都以 txt 结尾
rename "s//.txt//" * # 把所有以 .txt 结尾的文件名的.txt 删掉
```
-### stat
+### 3.10. stat
> stat 命令用于显示文件的状态信息。stat 命令的输出信息比 ls 命令的输出信息要更详细。
>
@@ -296,7 +269,7 @@ rename "s//.txt//" * # 把所有以 .txt 结尾的文件名的.txt
stat myfile
```
-### file
+### 3.11. file
> file 命令用来探测给定文件的类型。file 命令对文件的检查分为文件系统、魔法幻数检查和语言检查 3 个过程。
>
@@ -311,7 +284,7 @@ file -i install.log # 显示 MIME 类型
file -L /var/spool/mail # 显示符号链接的文件类型
```
-### chmod
+### 3.12. chmod
> chmod 命令用来变更文件或目录的权限。在 UNIX 系统家族里,文件或目录权限的控制分别以读取、写入、执行 3 种一般权限来区分,另有 3 种特殊权限可供运用。用户可以使用 chmod 指令去变更文件与目录的权限,设置方式采用文字或数字代号皆可。符号连接的权限无法变更,如果用户对符号连接修改权限,其改变会作用在被连接的原始文件。
>
@@ -350,7 +323,7 @@ chmod a+x f01 # 对文件f01的u,g,o都设置可执行属性
chmod -R 755 /home/wwwroot/*
```
-### chown
+### 3.13. chown
> chown 命令改变某个文件或目录的所有者和所属的组,该命令可以向某个用户授权,使该用户变成指定文件的所有者或者改变文件所属的组。用户可以是用户或者是用户 D,用户组可以是组名或组 id。文件名可以使由空格分开的文件列表,在文件名中可以包含通配符。
>
@@ -365,7 +338,7 @@ chmod -R 755 /home/wwwroot/*
chown -R liu /usr/meng
```
-### locate
+### 3.14. locate
> locate 命令和 slocate 命令都用来查找文件或目录。
>
@@ -380,7 +353,7 @@ locate pwd # 查找和 pwd 相关的所有文件
locate /etc/sh # 搜索 etc 目录下所有以 sh 开头的文件
```
-### find
+### 3.15. find
> find 命令用来在指定目录下查找文件。任何位于参数之前的字符串都将被视为欲查找的目录名。如果使用该命令时,不设置任何参数,则 find 命令将在当前目录下查找子目录与文件。并且将查找到的子目录和文件全部进行显示。
>
@@ -413,7 +386,7 @@ find . -iregex ".*\(\.txt\|\.pdf\)$"
find /home ! -name "*.txt"
```
-### cp
+### 3.16. cp
> cp 命令用来将一个或多个源文件或者目录复制到指定的目的文件或目录。它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在的目录下。cp 命令还支持同时复制多个文件,当一次复制多个文件时,目标文件参数必须是一个已经存在的目录,否则将出现错误。
>
@@ -421,7 +394,7 @@ find /home ! -name "*.txt"
示例:
-#### 参数
+#### 3.16.1. 参数
- 源文件:制定源文件列表。默认情况下,cp 命令不能复制目录,如果要复制目录,则必须使用`-R`选项;
- 目标文件:指定目标文件。当“源文件”为多个文件时,要求“目标文件”为指定的目录。
@@ -442,7 +415,7 @@ cp -rf /usr/men/* /usr/zh
cp -i /usr/men m*.c /usr/zh
```
-### scp
+### 3.17. scp
> scp 命令用于在 Linux 下进行远程拷贝文件的命令,和它类似的命令有 cp,不过 cp 只是在本机进行拷贝不能跨服务器,而且 scp 传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读 read only system 时,用 scp 可以帮你把文件移出来。另外,scp 还非常不占资源,不会提高多少系统负荷,在这一点上,rsync 就远远不及它了。虽然 rsync 比 scp 会快一点,但当小文件众多的情况下,rsync 会导致硬盘 I/O 非常高,而 scp 基本不影响系统正常使用。
@@ -458,7 +431,7 @@ scp -r @:
scp -r test root@192.168.0.1:/opt
```
-#### 免密码传输
+#### 3.17.1. 免密码传输
(1)生成 ssh 公私钥对
@@ -477,7 +450,7 @@ cat ~/.ssh/id_rsa.pub.tmp >> ~/.ssh/authorized_keys
rm ~/.ssh/id_rsa.pub.tmp
```
-### mv
+### 3.18. mv
> mv 命令用来对文件或目录重新命名,或者将文件从一个目录移到另一个目录中。source 表示源文件或目录,target 表示目标文件或目录。如果将一个文件移到一个已经存在的目标文件中,则目标文件的内容将被覆盖。
>
@@ -503,7 +476,7 @@ mv -f *.txt /home/office # 无条件覆盖已经存在的文件
mv -bv *.txt /home/office # 复制时创建备份
```
-### rm
+### 3.19. rm
> rm 命令可以删除一个目录中的一个或多个文件或目录,也可以将某个目录及其下属的所有文件及其子目录均删除掉。对于链接文件,只是删除整个链接文件,而原有文件保持不变。
>
diff --git "a/docs/linux/cli/Linux\346\226\207\344\273\266\345\216\213\347\274\251\345\222\214\350\247\243\345\216\213.md" b/docs/linux/cli/linux-cli-file-compress.md
similarity index 87%
rename from "docs/linux/cli/Linux\346\226\207\344\273\266\345\216\213\347\274\251\345\222\214\350\247\243\345\216\213.md"
rename to docs/linux/cli/linux-cli-file-compress.md
index 1185ff30..ba3fad16 100644
--- "a/docs/linux/cli/Linux\346\226\207\344\273\266\345\216\213\347\274\251\345\222\214\350\247\243\345\216\213.md"
+++ b/docs/linux/cli/linux-cli-file-compress.md
@@ -1,37 +1,16 @@
----
-title: Linux 文件压缩和解压
-date: 2018-02-27
-categories:
- - linux
-tags:
- - linux
- - command
----
-
# Linux 文件压缩和解压
> 关键词:`tar`, `gzip`, `zip`, `unzip`
-
-
-- [Linux 文件压缩和解压要点](#linux-文件压缩和解压要点)
-- [命令常见用法](#命令常见用法)
- - [tar](#tar)
- - [gzip](#gzip)
- - [zip](#zip)
- - [unzip](#unzip)
-
-
-
-## Linux 文件压缩和解压要点
+## 1. Linux 文件压缩和解压要点
- 压缩和解压 tar 文件 - 使用 [tar](#tar)
- 压缩和解压 gz 文件 - 使用 [gzip](#gzip)
- 压缩和解压 zip 文件 - 分别使用 [zip](#zip)、[unzip](#unzip)
-## 命令常见用法
+## 2. 命令常见用法
-### tar
+### 2.1. tar
> tar 命令可以为 linux 的文件和目录创建档案。利用 tar,可以为某一特定文件创建档案(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件。tar 最初被用来在磁带上创建档案,现在,用户可以在任何设备上创建档案。利用 tar 命令,可以把一大堆的文件和目录全部打包成一个文件,这对于备份文件或将几个文件组合成为一个文件以便于网络传输是非常有用的。
>
@@ -49,7 +28,7 @@ tar -zxvf log.tar.gz # 将 tar 包解压缩
tar -zxvf log30.tar.gz log2013.log # 只将 tar 内的部分文件解压出来
```
-### gzip
+### 2.2. gzip
> gzip 命令用来压缩文件。gzip 是个使用广泛的压缩程序,文件经它压缩过后,其名称后面会多出“.gz”扩展名。
>
@@ -68,7 +47,7 @@ gzip -rv test/ # 递归的压缩目录
gzip -dr test/ # 递归地解压目录
```
-### zip
+### 2.3. zip
> zip 命令可以用来解压缩文件,或者对文件进行打包操作。zip 是个使用广泛的压缩程序,文件经它压缩后会另外产生具有“.zip”扩展名的压缩文件。
>
@@ -81,7 +60,7 @@ gzip -dr test/ # 递归地解压目录
zip -q -r html.zip /home/Blinux/html
```
-### unzip
+### 2.4. unzip
> unzip 命令用于解压缩由 zip 命令压缩的“.zip”压缩包。
>
diff --git "a/docs/linux/cli/Linux\346\226\207\344\273\266\345\206\205\345\256\271\346\237\245\347\234\213\347\274\226\350\276\221.md" b/docs/linux/cli/linux-cli-file.md
similarity index 89%
rename from "docs/linux/cli/Linux\346\226\207\344\273\266\345\206\205\345\256\271\346\237\245\347\234\213\347\274\226\350\276\221.md"
rename to docs/linux/cli/linux-cli-file.md
index 5fc4409b..03e5b3e4 100644
--- "a/docs/linux/cli/Linux\346\226\207\344\273\266\345\206\205\345\256\271\346\237\245\347\234\213\347\274\226\350\276\221.md"
+++ b/docs/linux/cli/linux-cli-file.md
@@ -1,34 +1,8 @@
----
-title: Linux 文件内容查看编辑
-date: 2018-02-27
-categories:
- - linux
-tags:
- - linux
- - command
----
-
# Linux 文件内容查看编辑
> 关键词:`cat`, `head`, `tail`, `more`, `less`, `sed`, `vi`, `grep`
-
-
-- [Linux 文件内容查看编辑要点](#linux-文件内容查看编辑要点)
-- [命令常见用法](#命令常见用法)
- - [cat](#cat)
- - [head](#head)
- - [tail](#tail)
- - [more](#more)
- - [less](#less)
- - [sed](#sed)
- - [vi](#vi)
- - [grep](#grep)
-- [参考资料](#参考资料)
-
-
-
-## Linux 文件内容查看编辑要点
+## 1. Linux 文件内容查看编辑要点
- 连接文件并打印到标准输出设备 - 使用 [cat](#cat)
- 显示指定文件的开头若干行 - 使用 [head](#head)
@@ -39,9 +13,9 @@ tags:
- 文本编辑器 - 使用 [vi](#vi)
- 使用正则表达式搜索文本,并把匹配的行打印出来 - 使用 [grep](#grep)
-## 命令常见用法
+## 2. 命令常见用法
-### cat
+### 2.1. cat
> cat 命令用于连接文件并打印到标准输出设备上。
>
@@ -55,13 +29,13 @@ cat m1 m2 # 同时显示文件 ml 和 m2 的内容
cat m1 m2 > file # 将文件 ml 和 m2 合并后放入文件 file 中
```
-### head
+### 2.2. head
> head 命令用于显示文件的开头内容。在默认情况下,head 命令显示文件的头部 10 行内容。
>
> 参考:http://man.linuxde.net/head
-### tail
+### 2.3. tail
> tail 命令用于显示文件的尾部内容。在默认情况下,tail 命令显示文件的尾部 10 行内容。如果给定的文件不止一个,则在显示的每个文件前面加一个文件名标题。如果没有指定文件或者文件名为“-”,则读取标准输入。
>
@@ -75,7 +49,7 @@ tail -n +20 file # 显示文件file的内容,从第20行至文件末尾
tail -c 10 file # 显示文件file的最后10个字符
```
-### more
+### 2.4. more
> more 命令是一个基于 vi 编辑器文本过滤器,它以全屏幕的方式按页显示文本文件的内容,支持 vi 中的关键字定位操作。more 名单中内置了若干快捷键,常用的有 H(获得帮助信息),Enter(向下翻滚一行),空格(向下滚动一屏),Q(退出命令)。
>
@@ -100,7 +74,7 @@ more -dc file
more -c -10 file
```
-### less
+### 2.5. less
less 命令的作用与 more 十分相似,都可以用来浏览文字档案的内容,不同的是 less 命令允许用户向前或向后浏览文件,而 more 命令只能向前浏览。用 less 命令显示文件时,用 PageUp 键向上翻页,用 PageDown 键向下翻页。要退出 less 程序,应按 Q 键。
@@ -110,7 +84,7 @@ less 命令的作用与 more 十分相似,都可以用来浏览文字档案的
less /var/log/shadowsocks.log
```
-### sed
+### 2.6. sed
> sed 是一种流编辑器,它是文本处理工具,能够完美的配合正则表达式使用,功能不同凡响。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed 主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
>
@@ -147,15 +121,15 @@ sed '$d' file
sed '/^test/'d file
```
-### vi
+### 2.7. vi
> vi 命令是 UNIX 操作系统和类 UNIX 操作系统中最通用的全屏幕纯文本编辑器。Linux 中的 vi 编辑器叫 vim,它是 vi 的增强版(vi Improved),与 vi 编辑器完全兼容,而且实现了很多增强功能。
>
> 参考:http://man.linuxde.net/vi
>
-> 引申阅读:[Vim 快速指南](https://github.com/dunwu/OS/blob/master/docs/vim.md)
+> 引申阅读:[Vim 入门指南](https://github.com/dunwu/OS/blob/master/docs/vim.md)
-### grep
+### 2.8. grep
> grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
>
@@ -183,6 +157,6 @@ $ grep "main()" . -r --exclude "README"
$ grep "main()" . -r --exclude-from filelist
```
-## 参考资料
+## 3. 参考资料
- [Linux 命令大全](http://man.linuxde.net/)
diff --git "a/docs/linux/cli/Linux\347\241\254\344\273\266\347\256\241\347\220\206.md" b/docs/linux/cli/linux-cli-hardware.md
similarity index 92%
rename from "docs/linux/cli/Linux\347\241\254\344\273\266\347\256\241\347\220\206.md"
rename to docs/linux/cli/linux-cli-hardware.md
index bae5e857..7a66969b 100644
--- "a/docs/linux/cli/Linux\347\241\254\344\273\266\347\256\241\347\220\206.md"
+++ b/docs/linux/cli/linux-cli-hardware.md
@@ -1,30 +1,8 @@
----
-title: Linux 硬件管理
-date: 2018-02-27
-categories:
- - linux
-tags:
- - linux
- - command
----
-
# Linux 硬件管理
> 关键词:`df`, `du`, `top`, `free`, `iotop`
-
-
-- [Linux 硬件管理要点](#linux-硬件管理要点)
-- [命令常见用法](#命令常见用法)
- - [df](#df)
- - [du](#du)
- - [top](#top)
- - [free](#free)
- - [iotop](#iotop)
-
-
-
-## Linux 硬件管理要点
+## 1. Linux 硬件管理要点
- 查看磁盘空间 - 使用 [df](#df)
- 查看文件或目录的磁盘空间 - 使用 [du](#du)
@@ -32,9 +10,9 @@ tags:
- 查看已使用和未使用的内存 - 使用 [free](#free)
- 查看磁盘 I/O 使用状况 - 使用 [iotop](#iotop)
-## 命令常见用法
+## 2. 命令常见用法
-### df
+### 2.1. df
> df 命令用于显示磁盘分区上的可使用的磁盘空间。默认显示单位为 KB。可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息。
>
@@ -72,7 +50,7 @@ tmpfs 1032204 0 1032204 0% /dev/shm
none 0 0 0 - /proc/sys/fs/binfmt_misc
```
-### du
+### 2.2. du
> du 命令也是查看使用空间的,但是与 df 命令不同的是:du 命令是对文件和目录磁盘使用的空间的查看,还是和 df 命令有一些区别的。
>
@@ -124,13 +102,13 @@ root@localhost [test]# du
32 scf
```
-### top
+### 2.3. top
> top 命令可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用工具。通过 top 命令所提供的互动式界面,用热键可以管理。
>
> 参考:http://man.linuxde.net/top
-### free
+### 2.4. free
> free 命令可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区。
>
@@ -151,7 +129,7 @@ Mem: 2016 1973 42 0 163 1497
Swap: 4094 0 4094
```
-### iotop
+### 2.5. iotop
> iotop 命令是一个用来监视磁盘 I/O 使用状况的 top 类工具。iotop 具有与 top 相似的 UI,其中包括 PID、用户、I/O、进程等相关信息。Linux 下的 IO 统计工具如 iostat,nmon 等大多数是只能统计到 per 设备的读写情况,如果你想知道每个进程是如何使用 IO 的就比较麻烦,使用 iotop 命令可以很方便的查看。
>
diff --git "a/docs/linux/cli/\346\237\245\347\234\213Linux\345\221\275\344\273\244\345\270\256\345\212\251\344\277\241\346\201\257.md" b/docs/linux/cli/linux-cli-help.md
similarity index 88%
rename from "docs/linux/cli/\346\237\245\347\234\213Linux\345\221\275\344\273\244\345\270\256\345\212\251\344\277\241\346\201\257.md"
rename to docs/linux/cli/linux-cli-help.md
index e0e60782..83d08447 100644
--- "a/docs/linux/cli/\346\237\245\347\234\213Linux\345\221\275\344\273\244\345\270\256\345\212\251\344\277\241\346\201\257.md"
+++ b/docs/linux/cli/linux-cli-help.md
@@ -1,34 +1,11 @@
----
-title: 查看 Linux 命令帮助信息
-date: 2018-09-26
-categories:
- - linux
-tags:
- - linux
- - command
----
-
# 查看 Linux 命令帮助信息
> Linux 中有非常多的命令,想全部背下来是很困难的事。所以,我认为学习 Linux 的第一步,就是了解如何快速检索命令说明。
>
> 关键词:`help`, `whatis`, `info`, `which`, `whereis`, `man`
-
-
-- [查看 Linux 命令帮助信息的要点](#查看-linux-命令帮助信息的要点)
-- [命令常见用法](#命令常见用法)
- - [help](#help)
- - [whatis](#whatis)
- - [info](#info)
- - [which](#which)
- - [whereis](#whereis)
- - [man](#man)
-- [参考资料](#参考资料)
-
-
-## 查看 Linux 命令帮助信息的要点
+## 1. 查看 Linux 命令帮助信息的要点
- 查看 Shell 内部命令的帮助信息 - 使用 [help](#help)
- 查看命令的简要说明 - 使用 [whatis](#whatis)
@@ -43,15 +20,15 @@ tags:
> - [Linux 命令大全](http://man.linuxde.net/)
> - [linux-command](https://github.com/jaywcjlove/linux-command)
-## 命令常见用法
+## 2. 命令常见用法
-### help
+### 2.1. help
> help 命令用于查看 Shell 内部命令的帮助信息。而对于外部命令的帮助信息只能使用 man 或者 info 命令查看。
>
> 参考:http://man.linuxde.net/help
-### whatis
+### 2.2. whatis
> whatis 用于查询一个命令执行什么功能。
>
@@ -67,7 +44,7 @@ $ whatis man
$ whatis -w "loca*"
```
-### info
+### 2.3. info
> info 是 Linux 下 info 格式的帮助指令。
>
@@ -80,7 +57,7 @@ $ whatis -w "loca*"
$ info man
```
-### which
+### 2.4. which
> which 命令用于查找并显示给定命令的绝对路径,环境变量 PATH 中保存了查找命令时需要遍历的目录。which 指令会在环境变量$PATH 设置的目录里查找符合条件的文件。也就是说,使用 which 命令,就可以看到某个系统命令是否存在,以及执行的到底是哪一个位置的命令。
>
@@ -101,7 +78,7 @@ cd: shell built-in command
cd 这个常用的命令竟然找不到啊!为什么呢?这是因为 cd 是 bash 内建的命令!但是 which 默认是找 PATH 内所规范的目录,所以当然一定找不到的!
-### whereis
+### 2.5. whereis
> whereis 命令用来定位指令的二进制程序、源代码文件和 man 手册页等相关文件的路径。
>
@@ -115,7 +92,7 @@ cd 这个常用的命令竟然找不到啊!为什么呢?这是因为 cd 是
whereis git # 将相关的文件都查找出来
```
-### man
+### 2.6. man
> man 命令是 Linux 下的帮助指令,通过 man 指令可以查看 Linux 中的指令帮助、配置文件帮助和编程帮助等信息。
>
@@ -129,7 +106,7 @@ $ man 3 printf # 查看 printf 命令的帮助手册中的第 3 类
$ man -k keyword # 根据命令中部分关键字来查询命令
```
-#### man 要点
+#### 2.6.1. man 要点
在 man 的帮助手册中,可以使用 page up 和 page down 来上下翻页。
@@ -164,6 +141,6 @@ printf [builtins](1) - bash built-in commands, see bash(1)
$ man 3 printf
```
-## 参考资料
+## 3. 参考资料
https://linuxtools-rst.readthedocs.io/zh_CN/latest/base/01_use_man.html
diff --git "a/docs/linux/cli/Linux\347\275\221\347\273\234\347\256\241\347\220\206.md" b/docs/linux/cli/linux-cli-net.md
similarity index 93%
rename from "docs/linux/cli/Linux\347\275\221\347\273\234\347\256\241\347\220\206.md"
rename to docs/linux/cli/linux-cli-net.md
index ea01a90a..a3b7c142 100644
--- "a/docs/linux/cli/Linux\347\275\221\347\273\234\347\256\241\347\220\206.md"
+++ b/docs/linux/cli/linux-cli-net.md
@@ -1,42 +1,8 @@
----
-title: Linux 网络管理
-date: 2018-02-27
-categories:
- - linux
-tags:
- - linux
- - command
----
-
# Linux 网络管理
> 关键词:`curl`, `wget`, `telnet`, `ip`, `hostname`, `ifconfig`, `route`, `ssh`, `ssh-keygen`, `firewalld`, `iptables`, `host`, `nslookup`, `nc`/`netcat`, `ping`, `traceroute`, `netstat`
-
-
-- [Linux 网络应用要点](#linux-网络应用要点)
-- [命令常见用法](#命令常见用法)
- - [curl](#curl)
- - [wget](#wget)
- - [telnet](#telnet)
- - [ip](#ip)
- - [hostname](#hostname)
- - [ifconfig](#ifconfig)
- - [route](#route)
- - [ssh](#ssh)
- - [ssh-keygen](#ssh-keygen)
- - [firewalld](#firewalld)
- - [iptables](#iptables)
- - [host](#host)
- - [nslookup](#nslookup)
- - [nc/netcat](#ncnetcat)
- - [ping](#ping)
- - [traceroute](#traceroute)
- - [netstat](#netstat)
-
-
-
-## Linux 网络应用要点
+## 1. Linux 网络应用要点
- 下载文件 - 使用 [curl](#curl)、[wget](#wget)
- telnet 方式登录远程主机,对远程主机进行管理 - 使用 [telnet](#telnet)
@@ -54,9 +20,9 @@ tags:
- 追踪数据在网络上的传输时的全部路径 - 使用 [traceroute](#traceroute)
- 查看当前工作的端口信息 - 使用 [netstat](#netstat)
-## 命令常见用法
+## 2. 命令常见用法
-### curl
+### 2.1. curl
> curl 命令是一个利用 URL 规则在命令行下工作的文件传输工具。它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称 curl 为下载工具。作为一款强力工具,curl 支持包括 HTTP、HTTPS、ftp 等众多协议,还支持 POST、cookies、认证、从指定偏移处下载部分文件、用户代理字符串、限速、文件大小、进度条等特征。做网页处理流程和数据检索自动化,curl 可以祝一臂之力。
>
@@ -73,7 +39,7 @@ $ curl http://man.linuxde.net/test.iso -o filename.iso --progress
########################################## 100.0%
```
-### wget
+### 2.2. wget
> wget 命令用来从指定的 URL 下载文件。
>
@@ -86,7 +52,7 @@ $ curl http://man.linuxde.net/test.iso -o filename.iso --progress
$ wget http://www.linuxde.net/testfile.zip
```
-### telnet
+### 2.3. telnet
> telnet 命令用于登录远程主机,对远程主机进行管理。
>
@@ -107,7 +73,7 @@ Password:
Login incorrect
```
-### ip
+### 2.4. ip
> ip 命令用来查看或操纵 Linux 主机的路由、网络设备、策略路由和隧道,是 Linux 下较新的功能强大的网络配置工具。
>
@@ -137,7 +103,7 @@ $ ip route del default # 删除默认路由
$ ip route delete 192.168.1.0/24 dev eth0 # 删除路由
```
-### hostname
+### 2.5. hostname
> hostname 命令用于查看和设置系统的主机名称。环境变量 HOSTNAME 也保存了当前的主机名。在使用 hostname 命令设置主机名后,系统并不会永久保存新的主机名,重新启动机器之后还是原来的主机名。如果需要永久修改主机名,需要同时修改 `/etc/hosts` 和 `/etc/sysconfig/network` 的相关内容。
>
@@ -150,7 +116,7 @@ $ hostname
AY1307311912260196fcZ
```
-### ifconfig
+### 2.6. ifconfig
> ifconfig 命令被用于查看和配置 Linux 内核中网络接口的网络参数。用 ifconfig 命令配置的网卡信息,在网卡重启后机器重启后,配置就不存在。要想将上述的配置信息永远的存的电脑里,那就要修改网卡的配置文件了。
>
@@ -178,7 +144,7 @@ lo Link encap:Local Loopback
RX bytes:5079451 (4.8 MiB) TX bytes:5079451 (4.8 MiB)
```
-### route
+### 2.7. route
> route 命令用来查看和设置 Linux 内核中的网络路由表,route 命令设置的路由主要是静态路由。要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现。
>
@@ -205,7 +171,7 @@ route add default gw 192.168.120.240 # 添加默认网关
route del default gw 192.168.120.240 # 删除默认网关
```
-### ssh
+### 2.8. ssh
> ssh 命令是 openssh 套件中的客户端连接工具,可以给予 ssh 加密协议实现安全的远程登录服务器。
>
@@ -222,19 +188,19 @@ ssh -p 2211 root@140.206.185.170
引申阅读:[ssh 背后的故事](https://linux.cn/article-8476-1.html)
-### ssh-keygen
+### 2.9. ssh-keygen
> ssh-keygen 命令用于为 ssh 生成、管理和转换认证密钥,它支持 RSA 和 DSA 两种认证密钥。
>
> 参考:http://man.linuxde.net/ssh-keygen
-### firewalld
+### 2.10. firewalld
> firewalld 命令是 Linux 上的防火墙软件(Centos7 默认防火墙)。
>
> 参考:https://www.cnblogs.com/moxiaoan/p/5683743.html
-#### firewalld 的基本使用
+#### 2.10.1. firewalld 的基本使用
- 启动 - systemctl start firewalld
- 关闭 - systemctl stop firewalld
@@ -242,7 +208,7 @@ ssh -p 2211 root@140.206.185.170
- 开机禁用 - systemctl disable firewalld
- 开机启用 - systemctl enable firewalld
-#### 使用 systemctl 管理 firewalld 服务
+#### 2.10.2. 使用 systemctl 管理 firewalld 服务
systemctl 是 CentOS7 的服务管理工具中主要的工具,它融合之前 service 和 chkconfig 的功能于一体。
@@ -256,7 +222,7 @@ systemctl 是 CentOS7 的服务管理工具中主要的工具,它融合之前
- 查看已启动的服务列表 - systemctl list-unit-files|grep enabled
- 查看启动失败的服务列表 - systemctl --failed
-#### 配置 firewalld-cmd
+#### 2.10.3. 配置 firewalld-cmd
- 查看版本 - firewall-cmd --version
- 查看帮助 - firewall-cmd --help
@@ -269,14 +235,14 @@ systemctl 是 CentOS7 的服务管理工具中主要的工具,它融合之前
- 取消拒绝状态 - firewall-cmd --panic-off
- 查看是否拒绝 - firewall-cmd --query-panic
-#### 在防火墙中开放一个端口
+#### 2.10.4. 在防火墙中开放一个端口
- 添加(--permanent 永久生效,没有此参数重启后失效) - firewall-cmd --zone=public --add-port=80/tcp --permanent
- 重新载入 - firewall-cmd --reload
- 查看 - firewall-cmd --zone= public --query-port=80/tcp
- 删除 - firewall-cmd --zone= public --remove-port=80/tcp --permanent
-### iptables
+### 2.11. iptables
> iptables 命令是 Linux 上常用的防火墙软件,是 netfilter 项目的一部分。可以直接配置,也可以通过许多前端和图形界面配置。
>
@@ -320,7 +286,7 @@ Chain OUTPUT (policy ACCEPT 3382K packets, 1819M bytes)
5075 589K ACCEPT all -- * lo 0.0.0.0/0 0.0.0.0/0
```
-### host
+### 2.12. host
> host 命令是常用的分析域名查询工具,可以用来测试域名系统工作是否正常。
>
@@ -347,7 +313,7 @@ www.jsdig.com. 463 IN CNAME host.1.jsdig.com.
Received 54 bytes from 202.96.104.15#53 in 0 ms
```
-### nslookup
+### 2.13. nslookup
> nslookup 命令是常用域名查询工具,就是查 DNS 信息用的命令。
>
@@ -366,7 +332,7 @@ Name: host.1.jsdig.com
Address: 100.42.212.8
```
-### nc/netcat
+### 2.14. nc/netcat
> nc 命令是 netcat 命令的简称,都是用来设置路由器。
>
@@ -386,7 +352,7 @@ Address: 100.42.212.8
[root@localhost ~]# nc -u -z -w2 192.168.0.1 1-1000 # 扫描192.168.0.3 的端口 范围是 1-1000
```
-### ping
+### 2.15. ping
> ping 命令用来测试主机之间网络的连通性。执行 ping 指令会使用 ICMP 传输协议,发出要求回应的信息,若远端主机的网络功能没有问题,就会回应该信息,因而得知该主机运作正常。
>
@@ -408,7 +374,7 @@ PING host.1.jsdig.com (100.42.212.8) 56(84) bytes of data.
rtt min/avg/max/mdev = 174.068/176.916/178.182/1.683 ms
```
-### traceroute
+### 2.16. traceroute
> traceroute 命令用于追踪数据包在网络上的传输时的全部路径,它默认发送的数据包大小是 40 字节。
>
@@ -433,7 +399,7 @@ traceroute to www.58.com (211.151.111.30), 30 hops max, 40 byte packets
12 211.151.111.30 (211.151.111.30) 35.161 ms 35.938 ms 36.005 ms
```
-### netstat
+### 2.17. netstat
> netstat 命令用来打印 Linux 中网络系统的状态信息,可让你得知整个 Linux 系统的网络情况。
>
diff --git "a/docs/linux/cli/Linux\350\275\257\344\273\266\347\256\241\347\220\206.md" b/docs/linux/cli/linux-cli-software.md
similarity index 93%
rename from "docs/linux/cli/Linux\350\275\257\344\273\266\347\256\241\347\220\206.md"
rename to docs/linux/cli/linux-cli-software.md
index ad250ce3..64b1487e 100644
--- "a/docs/linux/cli/Linux\350\275\257\344\273\266\347\256\241\347\220\206.md"
+++ b/docs/linux/cli/linux-cli-software.md
@@ -1,27 +1,8 @@
----
-title: Linux 软件管理
-date: 2018-02-26
-categories:
- - linux
-tags:
- - linux
----
-
# Linux 软件管理
> 关键词:`rpm`, `yum`, `apt-get`
-
-
-- [rpm](#rpm)
-- [yum](#yum)
- - [yum 源](#yum-源)
-- [apt-get](#apt-get)
-- [参考资料](#参考资料)
-
-
-
-## rpm
+## 1. rpm
> rpm 命令是 RPM 软件包的管理工具。rpm 原本是 Red Hat Linux 发行版专门用来管理 Linux 各项套件的程序,由于它遵循 GPL 规则且功能强大方便,因而广受欢迎。逐渐受到其他发行版的采用。RPM 套件管理方式的出现,让 Linux 易于安装,升级,间接提升了 Linux 的适用度。
>
@@ -83,7 +64,7 @@ rpm -e proftpd-1
rpm -qa # 列出所有安装过的包
```
-## yum
+## 2. yum
> yum 命令是在 Fedora 和 RedHat 以及 SUSE 中基于 rpm 的软件包管理器,它可以使系统管理人员交互和自动化地更细与管理 RPM 软件包,能够从指定的服务器自动下载 RPM 包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软体包,无须繁琐地一次次下载、安装。
>
@@ -141,7 +122,7 @@ yum clean headers #清除缓存目录下的 headers
yum clean oldheaders #清除缓存目录下旧的 headers
```
-### yum 源
+### 2.1. yum 源
yum 的默认源是国外的,下载速度比较慢,所以最好替换为一个国内的 yum 源。
@@ -150,7 +131,7 @@ yum 的默认源是国外的,下载速度比较慢,所以最好替换为一
| | Centos6:http://mirrors.aliyun.com/repo/Centos-6.repo Centos7:http://mirrors.aliyun.com/repo/Centos-7.repo |
| | Centos6:http://mirrors.163.com/.help/CentOS6-Base-163.repo Centos7:http://mirrors.163.com/.help/CentOS7-Base-163.repo |
-> 注意:Cento5 已废弃,只能使用 http://vault.centos.org/ 替换,但由于是国外镜像,速度较慢。
+> 🔔 注意:Cento5 已废弃,只能使用 http://vault.centos.org/ 替换,但由于是国外镜像,速度较慢。
替换方法,以 aliyun CentOS7 为例:
@@ -161,7 +142,7 @@ yum clean all
yum makecache
```
-## apt-get
+## 3. apt-get
> apt-get 命令是 Debian Linux 发行版中的 APT 软件包管理工具。所有基于 Debian 的发行都使用这个包管理系统。deb 包可以把一个应用的文件包在一起,大体就如同 Windows 上的安装文件。
>
@@ -202,7 +183,7 @@ apt-get upgrade
apt-get dist-upgrade
```
-## 参考资料
+## 4. 参考资料
- http://man.linuxde.net/rpm
- http://man.linuxde.net/yum
diff --git "a/docs/linux/cli/Linux\347\263\273\347\273\237\347\256\241\347\220\206.md" b/docs/linux/cli/linux-cli-system.md
similarity index 93%
rename from "docs/linux/cli/Linux\347\263\273\347\273\237\347\256\241\347\220\206.md"
rename to docs/linux/cli/linux-cli-system.md
index 3e3a1852..703a5905 100644
--- "a/docs/linux/cli/Linux\347\263\273\347\273\237\347\256\241\347\220\206.md"
+++ b/docs/linux/cli/linux-cli-system.md
@@ -1,37 +1,8 @@
----
-title: Linux 系统管理
-date: 2018-02-27
-categories:
- - linux
-tags:
- - linux
- - command
----
-
# Linux 系统管理
> 关键词:`lsb_release`, `reboot`, `exit`, `shutdown`, `date`, `mount`, `umount`, `ps`, `kill`, `systemctl`, `service`, `crontab`
-
-
-- [Linux 系统管理要点](#linux-系统管理要点)
-- [命令常见用法](#命令常见用法)
- - [lsb_release](#lsb_release)
- - [reboot](#reboot)
- - [exit](#exit)
- - [shutdown](#shutdown)
- - [date](#date)
- - [mount](#mount)
- - [umount](#umount)
- - [ps](#ps)
- - [kill](#kill)
- - [systemctl](#systemctl)
- - [service](#service)
- - [crontab](#crontab)
-
-
-
-## Linux 系统管理要点
+## 1. Linux 系统管理要点
- 查看 Linux 系统发行版本
- 使用 [lsb_release](#lsb_release)(此命令适用于所有的 Linux 发行版本)
@@ -49,9 +20,9 @@ tags:
- 启动、停止、重启、关闭、显示系统服务(Centos7 以前),使用 [service](#service)
- 管理需要周期性执行的任务,使用 [crontab](#crontab)
-## 命令常见用法
+## 2. 命令常见用法
-### lsb_release
+### 2.1. lsb_release
lsb_release 不是 bash 默认命令,如果要使用,需要先安装。
@@ -60,7 +31,7 @@ lsb_release 不是 bash 默认命令,如果要使用,需要先安装。
1. 执行 `yum provides lsb_release`,查看支持 lsb_release 命令的包。
2. 选择合适版本,执行类似这样的安装命令:`yum install -y redhat-lsb-core-4.1-27.el7.centos.1.x86_64`
-### reboot
+### 2.2. reboot
> reboot 命令用来重新启动正在运行的 Linux 操作系统。
>
@@ -73,7 +44,7 @@ reboot # 重开机。
reboot -w # 做个重开机的模拟(只有纪录并不会真的重开机)。
```
-### exit
+### 2.3. exit
> exit 命令同于退出 shell,并返回给定值。在 shell 脚本中可以终止当前脚本执行。执行 exit 可使 shell 以指定的状态值退出。若不设置状态值参数,则 shell 以预设值退出。状态值 0 代表执行成功,其他值代表执行失败。
>
@@ -106,7 +77,7 @@ if [ "$EXCODE" == "0" ]; then
fi
```
-### shutdown
+### 2.4. shutdown
> shutdown 命令用来系统关机命令。shutdown 指令可以关闭所有程序,并依用户的需要,进行重新开机或关机的动作。
>
@@ -122,7 +93,7 @@ shutdown -h now
shutdown +5 "System will shutdown after 5 minutes"
```
-### date
+### 2.5. date
> date 命令是显示或设置系统时间与日期。
>
@@ -188,7 +159,7 @@ difference=$(( end - start ))
echo $difference seconds.
```
-### mount
+### 2.6. mount
> mount 命令用于挂载文件系统到指定的挂载点。此命令的最常用于挂载 cdrom,使我们可以访问 cdrom 中的数据,因为你将光盘插入 cdrom 中,Linux 并不会自动挂载,必须使用 Linux mount 命令来手动完成挂载。
>
@@ -208,7 +179,7 @@ mount -o ro /dev/hda1 /mnt
mount -o loop /tmp/image.iso /mnt/cdrom
```
-### umount
+### 2.7. umount
> umount 命令用于卸载已经挂载的文件系统。利用设备名或挂载点都能 umount 文件系统,不过最好还是通过挂载点卸载,以免使用绑定挂载(一个设备,多个挂载点)时产生混乱。
>
@@ -226,7 +197,7 @@ umount -v /mnt/mymount/
/tmp/diskboot.img umounted
```
-### ps
+### 2.8. ps
> ps 命令用于报告当前系统的进程状态。可以搭配 kill 指令随时中断、删除不必要的程序。ps 命令是最基本同时也是非常强大的进程查看命令,使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等,总之大部分信息都是可以通过执行该命令得到的。
>
@@ -242,7 +213,7 @@ ps aux | sort -rnk 4
ps aux | sort -nk 3
```
-### kill
+### 2.9. kill
> kill 命令用来删除执行中的程序或工作。kill 可将指定的信息送至程序。预设的信息为 SIGTERM(15),可将指定程序终止。若仍无法终止该程序,可使用 SIGKILL(9) 信息尝试强制删除程序。程序或工作的编号可利用 ps 指令或 job 指令查看。
>
@@ -280,7 +251,7 @@ kill 3268
-bash: kill: (3268) - 没有那个进程
```
-### systemctl
+### 2.10. systemctl
> systemctl 命令是系统服务管理器指令,它实际上将 service 和 chkconfig 这两个命令组合到一起。
>
@@ -305,7 +276,7 @@ systemctl status nfs-server.service
systemctl restart nfs-server.service
# 6.查看所有已启动的服务
-systemctl list -units --type=service
+systemctl list-units --type=service
# 7. 开启防火墙 22 端口
iptables -I INPUT -p tcp --dport 22 -j accept
@@ -316,7 +287,7 @@ sudo systemctl stop firewalld.service
sudo systemctl disable firewalld.service
```
-### service
+### 2.11. service
> service 命令是 Redhat Linux 兼容的发行版中用来控制系统服务的实用工具,它以启动、停止、重新启动和关闭系统服务,还可以显示所有系统服务的当前状态。
>
@@ -339,7 +310,7 @@ service network restart
弹出界面 eth0: [ 确定 ]
```
-### crontab
+### 2.12. crontab
> crontab 命令被用来提交和管理用户的需要周期性执行的任务,与 windows 下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动 crond 进程,crond 进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。
>
diff --git "a/docs/linux/cli/Linux\347\224\250\346\210\267\347\256\241\347\220\206.md" b/docs/linux/cli/linux-cli-user.md
similarity index 88%
rename from "docs/linux/cli/Linux\347\224\250\346\210\267\347\256\241\347\220\206.md"
rename to docs/linux/cli/linux-cli-user.md
index 5b050f45..91254414 100644
--- "a/docs/linux/cli/Linux\347\224\250\346\210\267\347\256\241\347\220\206.md"
+++ b/docs/linux/cli/linux-cli-user.md
@@ -1,34 +1,8 @@
----
-title: Linux 用户管理
-date: 2018-02-27
-categories:
- - linux
-tags:
- - linux
- - command
----
-
# Linux 用户管理
> 关键词:`groupadd`, `groupdel`, `groupmod`, `useradd`, `userdel`, `usermod`, `passwd`, `su`, `sudo`
-
-
-- [Linux 用户管理要点](#linux-用户管理要点)
-- [命令常见用法](#命令常见用法)
- - [groupadd](#groupadd)
- - [groupdel](#groupdel)
- - [groupmod](#groupmod)
- - [useradd](#useradd)
- - [userdel](#userdel)
- - [usermod](#usermod)
- - [passwd](#passwd)
- - [su](#su)
- - [sudo](#sudo)
-
-
-
-## Linux 用户管理要点
+## 1. Linux 用户管理要点
- 创建用户组 - 使用 [groupadd](#groupadd)
- 删除用户组 - 使用 [groupdel](#groupdel)
@@ -40,9 +14,9 @@ tags:
- 切换用户 - 使用 [su](#su)
- 当前用户想执行没有权限执行的命令时,使用其他用户身份去执行 - 使用 [sudo](#sudo)
-## 命令常见用法
+## 2. 命令常见用法
-### groupadd
+### 2.1. groupadd
> groupadd 命令用于创建一个新的用户组,新用户组的信息将被添加到系统文件中。
>
@@ -55,7 +29,7 @@ tags:
$ groupadd -g 344 jsdigname
```
-### groupdel
+### 2.2. groupdel
> groupdel 命令用于删除指定的用户组,本命令要修改的系统文件包括 `/ect/group` 和 `/ect/gshadow`。若该群组中仍包括某些用户,则必须先删除这些用户后,方能删除群组。
>
@@ -68,13 +42,13 @@ $ groupadd damon # 创建damon用户组
$ groupdel damon # 删除这个用户组
```
-### groupmod
+### 2.3. groupmod
> groupmod 命令更改群组识别码或名称。需要更改群组的识别码或名称时,可用 groupmod 指令来完成这项工作。
>
> 参考:http://man.linuxde.net/groupmod
-### useradd
+### 2.4. useradd
> useradd 命令用于 Linux 中创建的新的系统用户。useradd 可用来建立用户帐号。帐号建好之后,再用 passwd 设定帐号的密码.而可用 userdel 删除帐号。使用 useradd 指令所建立的帐号,实际上是保存在 `/etc/passwd` 文本文件中。
>
@@ -90,7 +64,7 @@ $ useradd –g sales jack –G company,employees # -g:加入主要组、-G
$ useradd caojh -u 544
```
-### userdel
+### 2.5. userdel
> userdel 命令用于删除给定的用户,以及与用户相关的文件。若不加选项,则仅删除用户帐号,而不删除相关文件。
>
@@ -105,7 +79,7 @@ $ userdel linuxde # 删除用户linuxde,但不删除其家目录及文
$ userdel -r linuxde # 删除用户linuxde,其 home 目录及文件一并删除;
```
-### usermod
+### 2.6. usermod
> usermod 命令用于修改用户的基本信息。usermod 命令不允许你改变正在线上的使用者帐号名称。当 usermod 命令用来改变 user id,必须确认这名 user 没在电脑上执行任何程序。你需手动更改使用者的 crontab 档。也需手动更改使用者的 at 工作档。采用 NIS server 须在 server 上更动相关的 NIS 设定。
>
@@ -127,7 +101,7 @@ $ usermod -L newuser1
$ usermod -U newuser1
```
-### passwd
+### 2.7. passwd
> passwd 命令用于设置用户的认证信息,包括用户密码、密码过期时间等。系统管理者则能用它管理系统用户的密码。只有管理者可以指定用户名称,一般用户只能变更自己的密码。
>
@@ -172,7 +146,7 @@ $ passwd -S linuxde # 查询linuxde用户密码状态;
Empty password. # 空密码,也就是没有密码;
```
-### su
+### 2.8. su
> su 命令用于切换当前用户身份到其他用户身份,变更时须输入所要变更的用户帐号与密码。
>
@@ -191,7 +165,7 @@ $ su root -f
$ su -test
```
-### sudo
+### 2.9. sudo
> sudo 命令用来以其他身份来执行命令,预设的身份为 root。在 `/etc/sudoers` 中设置了可执行 sudo 指令的用户。若其未经授权的用户企图使用 sudo,则会发出警告的邮件给管理员。用户使用 sudo 时,必须先输入密码,之后有 5 分钟的有效期限,超过期限则必须重新输入密码。
>
@@ -208,14 +182,14 @@ $ sudo -l
$ sudo -L
```
-#### 给普通用户授权 sudo
+#### 2.9.1. 给普通用户授权 sudo
假设要给普通用户 mary 配置 sudo 权限:
1. `/etc/sudoers` 文件存放了 sudo 的相关用户,但是默认是没有写权限的,所以需要设为可写:`chmod u+w /etc/sudoers`
-2. 在该文件中添加 `mary ALL=(ALL) ALL` ,保存并退出,让 mary 具有 sudo 的所有权限
+2. 在该文件中添加 `mary ALL=(ALL) ALL` ,保存并退出,让 mary 具有 sudo 的所有权限
3. 再将 `/etc/sudoers` 的权限恢复到默认状态:`chmod u-w /etc/sudoers`
-#### 免密码授权 sudo
+#### 2.9.2. 免密码授权 sudo
-与给普通用户授权 sudo 类似,区别仅在于第 2 步:`mary ALL=(ALL) NOPASSWD: ALL`。
+与给普通用户授权 sudo 类似,区别仅在于第 2 步:`mary ALL=(ALL) NOPASSWD: ALL`。
diff --git a/docs/linux/cli/scp.md b/docs/linux/cli/scp.md
new file mode 100644
index 00000000..1af18c81
--- /dev/null
+++ b/docs/linux/cli/scp.md
@@ -0,0 +1,83 @@
+# scp
+
+加密的方式在本地主机和远程主机之间复制文件
+
+## 补充说明
+
+**scp 命令** 用于在 Linux 下进行远程拷贝文件的命令,和它类似的命令有 cp,不过 cp 只是在本机进行拷贝不能跨服务器,而且 scp 传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读 read only system 时,用 scp 可以帮你把文件移出来。另外,scp 还非常不占资源,不会提高多少系统负荷,在这一点上,rsync 就远远不及它了。虽然 rsync 比 scp 会快一点,但当小文件众多的情况下,rsync 会导致硬盘 I/O 非常高,而 scp 基本不影响系统正常使用。
+
+### 语法
+
+```shell
+scp(选项)(参数)
+```
+
+### 选项
+
+```shell
+-1:使用ssh协议版本1;
+-2:使用ssh协议版本2;
+-4:使用ipv4;
+-6:使用ipv6;
+-B:以批处理模式运行;
+-C:使用压缩;
+-F:指定ssh配置文件;
+-i:identity_file 从指定文件中读取传输时使用的密钥文件(例如亚马逊云pem),此参数直接传递给ssh;
+-l:指定宽带限制;
+-o:指定使用的ssh选项;
+-P:指定远程主机的端口号;
+-p:保留文件的最后修改时间,最后访问时间和权限模式;
+-q:不显示复制进度;
+-r:以递归方式复制。
+```
+
+### 参数
+
+- 源文件:指定要复制的源文件。
+- 目标文件:目标文件。格式为`user@host:filename`(文件名为目标文件的名称)。
+
+### 实例
+
+从远程复制到本地的 scp 命令与上面的命令雷同,只要将从本地复制到远程的命令后面 2 个参数互换顺序就行了。
+
+**从远处复制文件到本地目录**
+
+```shell
+scp root@10.10.10.10:/opt/soft/nginx-0.5.38.tar.gz /opt/soft/
+```
+
+从 10.10.10.10 机器上的`/opt/soft/`的目录中下载 nginx-0.5.38.tar.gz 文件到本地`/opt/soft/`目录中。
+
+**从亚马逊云复制 OpenVPN 到本地目录**
+
+```shell
+scp -i amazon.pem ubuntu@10.10.10.10:/usr/local/openvpn_as/etc/exe/openvpn-connect-2.1.3.110.dmg openvpn-connect-2.1.3.110.dmg
+```
+
+从 10.10.10.10 机器上下载 openvpn 安装文件到本地当前目录来。
+
+**从远处复制到本地**
+
+```shell
+scp -r root@10.10.10.10:/opt/soft/mongodb /opt/soft/
+```
+
+从 10.10.10.10 机器上的`/opt/soft/`中下载 mongodb 目录到本地的`/opt/soft/`目录来。
+
+**上传本地文件到远程机器指定目录**
+
+```shell
+scp /opt/soft/nginx-0.5.38.tar.gz root@10.10.10.10:/opt/soft/scptest
+# 指定端口 2222
+scp -rp -P 2222 /opt/soft/nginx-0.5.38.tar.gz root@10.10.10.10:/opt/soft/scptest
+```
+
+复制本地`/opt/soft/`目录下的文件 nginx-0.5.38.tar.gz 到远程机器 10.10.10.10 的`opt/soft/scptest`目录。
+
+**上传本地目录到远程机器指定目录**
+
+```shell
+scp -r /opt/soft/mongodb root@10.10.10.10:/opt/soft/scptest
+```
+
+上传本地目录`/opt/soft/mongodb`到远程机器 10.10.10.10 上`/opt/soft/scptest`的目录中去。
diff --git a/docs/linux/cli/top.md b/docs/linux/cli/top.md
new file mode 100644
index 00000000..6b5f5756
--- /dev/null
+++ b/docs/linux/cli/top.md
@@ -0,0 +1,88 @@
+# top
+
+显示或管理执行中的程序
+
+## 补充说明
+
+**top 命令** 可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用工具。通过 top 命令所提供的互动式界面,用热键可以管理。
+
+### 语法
+
+```shell
+top(选项)
+```
+
+### 选项
+
+```shell
+-b:以批处理模式操作;
+-c:显示完整的治命令;
+-d:屏幕刷新间隔时间;
+-I:忽略失效过程;
+-s:保密模式;
+-S:累积模式;
+-i<时间>:设置间隔时间;
+-u<用户名>:指定用户名;
+-p<进程号>:指定进程;
+-n<次数>:循环显示的次数。
+```
+
+### top 交互命令
+
+在 top 命令执行过程中可以使用的一些交互命令。这些命令都是单字母的,如果在命令行中使用了-s 选项, 其中一些命令可能会被屏蔽。
+
+```shell
+h:显示帮助画面,给出一些简短的命令总结说明;
+k:终止一个进程;
+i:忽略闲置和僵死进程,这是一个开关式命令;
+q:退出程序;
+r:重新安排一个进程的优先级别;
+S:切换到累计模式;
+s:改变两次刷新之间的延迟时间(单位为s),如果有小数,就换算成ms。输入0值则系统将不断刷新,默认值是5s;
+f或者F:从当前显示中添加或者删除项目;
+o或者O:改变显示项目的顺序;
+l:切换显示平均负载和启动时间信息;
+m:切换显示内存信息;
+t:切换显示进程和CPU状态信息;
+c:切换显示命令名称和完整命令行;
+M:根据驻留内存大小进行排序;
+P:根据CPU使用百分比大小进行排序;
+T:根据时间/累计时间进行排序;
+w:将当前设置写入~/.toprc文件中。
+```
+
+### 实例
+
+```shell
+top - 09:44:56 up 16 days, 21:23, 1 user, load average: 9.59, 4.75, 1.92
+Tasks: 145 total, 2 running, 143 sleeping, 0 stopped, 0 zombie
+Cpu(s): 99.8%us, 0.1%sy, 0.0%ni, 0.2%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
+Mem: 4147888k total, 2493092k used, 1654796k free, 158188k buffers
+Swap: 5144568k total, 56k used, 5144512k free, 2013180k cached
+```
+
+**解释:**
+
+- top - 09:44:56[当前系统时间],
+- 16 days[系统已经运行了 16 天],
+- 1 user[个用户当前登录],
+- load average: 9.59, 4.75, 1.92[系统负载,即任务队列的平均长度]
+- Tasks: 145 total[总进程数],
+- 2 running[正在运行的进程数],
+- 143 sleeping[睡眠的进程数],
+- 0 stopped[停止的进程数],
+- 0 zombie[冻结进程数],
+- Cpu(s): 99.8%us[用户空间占用 CPU 百分比],
+- 0.1%sy[内核空间占用 CPU 百分比],
+- 0.0%ni[用户进程空间内改变过优先级的进程占用 CPU 百分比],
+- 0.2%id[空闲 CPU 百分比], 0.0%wa[等待输入输出的 CPU 时间百分比],
+- 0.0%hi[],
+- 0.0%st[],
+- Mem: 4147888k total[物理内存总量],
+- 2493092k used[使用的物理内存总量],
+- 1654796k free[空闲内存总量],
+- 158188k buffers[用作内核缓存的内存量]
+- Swap: 5144568k total[交换区总量],
+- 56k used[使用的交换区总量],
+- 5144512k free[空闲交换区总量],
+- 2013180k cached[缓冲的交换区总量],
diff --git a/docs/linux/cli/vmstat.md b/docs/linux/cli/vmstat.md
new file mode 100644
index 00000000..c8d52c03
--- /dev/null
+++ b/docs/linux/cli/vmstat.md
@@ -0,0 +1,95 @@
+# vmstat
+
+显示虚拟内存状态
+
+## 补充说明
+
+**vmstat 命令** 的含义为显示虚拟内存状态(“Viryual Memor Statics”),但是它可以报告关于进程、内存、I/O 等系统整体运行状态。
+
+### 语法
+
+```shell
+vmstat(选项)(参数)
+```
+
+### 选项
+
+```shell
+-a:显示活动内页;
+-f:显示启动后创建的进程总数;
+-m:显示slab信息;
+-n:头信息仅显示一次;
+-s:以表格方式显示事件计数器和内存状态;
+-d:报告磁盘状态;
+-p:显示指定的硬盘分区状态;
+-S:输出信息的单位。
+```
+
+### 参数
+
+- 事件间隔:状态信息刷新的时间间隔;
+- 次数:显示报告的次数。
+
+### 实例
+
+```shell
+vmstat 3
+procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
+ r b swpd free buff cache si so bi bo in cs us sy id wa st
+ 0 0 320 42188 167332 1534368 0 0 4 7 1 0 0 0 99 0 0
+ 0 0 320 42188 167332 1534392 0 0 0 0 1002 39 0 0 100 0 0
+ 0 0 320 42188 167336 1534392 0 0 0 19 1002 44 0 0 100 0 0
+ 0 0 320 42188 167336 1534392 0 0 0 0 1002 41 0 0 100 0 0
+ 0 0 320 42188 167336 1534392 0 0 0 0 1002 41 0 0 100 0 0
+```
+
+**字段说明:**
+
+Procs(进程)
+
+- r: 运行队列中进程数量,这个值也可以判断是否需要增加 CPU。(长期大于 1)
+- b: 等待 IO 的进程数量。
+
+Memory(内存)
+
+- swpd: 使用虚拟内存大小,如果 swpd 的值不为 0,但是 SI,SO 的值长期为 0,这种情况不会影响系统性能。
+- free: 空闲物理内存大小。
+- buff: 用作缓冲的内存大小。
+- cache: 用作缓存的内存大小,如果 cache 的值大的时候,说明 cache 处的文件数多,如果频繁访问到的文件都能被 cache 处,那么磁盘的读 IO bi 会非常小。
+
+Swap
+
+- si: 每秒从交换区写到内存的大小,由磁盘调入内存。
+- so: 每秒写入交换区的内存大小,由内存调入磁盘。
+
+注意:内存够用的时候,这 2 个值都是 0,如果这 2 个值长期大于 0 时,系统性能会受到影响,磁盘 IO 和 CPU 资源都会被消耗。有些朋友看到空闲内存(free)很少的或接近于 0 时,就认为内存不够用了,不能光看这一点,还要结合 si 和 so,如果 free 很少,但是 si 和 so 也很少(大多时候是 0),那么不用担心,系统性能这时不会受到影响的。
+
+IO(现在的 Linux 版本块的大小为 1kb)
+
+- bi: 每秒读取的块数
+- bo: 每秒写入的块数
+
+注意:随机磁盘读写的时候,这 2 个值越大(如超出 1024k),能看到 CPU 在 IO 等待的值也会越大。
+
+system(系统)
+
+- in: 每秒中断数,包括时钟中断。
+- cs: 每秒上下文切换数。
+
+注意:上面 2 个值越大,会看到由内核消耗的 CPU 时间会越大。
+
+CPU(以百分比表示)
+
+- us: 用户进程执行时间百分比(user time)
+
+us 的值比较高时,说明用户进程消耗的 CPU 时间多,但是如果长期超 50%的使用,那么我们就该考虑优化程序算法或者进行加速。
+
+- sy: 内核系统进程执行时间百分比(system time)
+
+sy 的值高时,说明系统内核消耗的 CPU 资源多,这并不是良性表现,我们应该检查原因。
+
+- wa: IO 等待时间百分比
+
+wa 的值高时,说明 IO 等待比较严重,这可能由于磁盘大量作随机访问造成,也有可能磁盘出现瓶颈(块操作)。
+
+- id: 空闲时间百分比
diff --git "a/docs/linux/cli/\345\221\275\344\273\244\350\241\214\347\232\204\350\211\272\346\234\257.md" "b/docs/linux/cli/\345\221\275\344\273\244\350\241\214\347\232\204\350\211\272\346\234\257.md"
index 8072d2af..5921f595 100644
--- "a/docs/linux/cli/\345\221\275\344\273\244\350\241\214\347\232\204\350\211\272\346\234\257.md"
+++ "b/docs/linux/cli/\345\221\275\344\273\244\350\241\214\347\232\204\350\211\272\346\234\257.md"
@@ -1,11 +1,10 @@
-> 转载自 https://github.com/jlevy/the-art-of-command-line
-
-*[Čeština](README-cs.md) ∙ [Deutsch](README-de.md) ∙ [Ελληνικά](README-el.md) ∙ [English](../README.md) ∙ [Español](README-es.md) ∙ [Français](README-fr.md) ∙ [Indonesia](README-id.md) ∙ [Italiano](README-it.md) ∙ [日本語](README-ja.md) ∙ [한국어](README-ko.md) ∙ [Português](README-pt.md) ∙ [Română](README-ro.md) ∙ [Русский](README-ru.md) ∙ [Slovenščina](README-sl.md) ∙ [Українська](README-uk.md) ∙ [简体中文](README-zh.md) ∙ [繁體中文](README-zh-Hant.md)*
+> 转载自 https://github.com/jlevy/the-art-of-command-line
+_[Čeština](README-cs.md) ∙ [Deutsch](README-de.md) ∙ [Ελληνικά](README-el.md) ∙ [English](../README.md) ∙ [Español](README-es.md) ∙ [Français](README-fr.md) ∙ [Indonesia](README-id.md) ∙ [Italiano](README-it.md) ∙ [日本語](README-ja.md) ∙ [한국어](README-ko.md) ∙ [Português](README-pt.md) ∙ [Română](README-ro.md) ∙ [Русский](README-ru.md) ∙ [Slovenščina](README-sl.md) ∙ [Українська](README-uk.md) ∙ [简体中文](README-zh.md) ∙ [繁體中文](README-zh-Hant.md)_
# 命令行的艺术
-
+
- [前言](#前言)
- [基础](#基础)
@@ -19,8 +18,7 @@
- [更多资源](#更多资源)
- [免责声明](#免责声明)
-
-
+
熟练使用命令行是一种常常被忽视,或被认为难以掌握的技能,但实际上,它会提高你作为工程师的灵活性以及生产力。本文是一份我在 Linux 上工作时,发现的一些命令行使用技巧的摘要。有些技巧非常基础,而另一些则相当复杂,甚至晦涩难懂。这篇文章并不长,但当你能够熟练掌握这里列出的所有技巧时,你就学会了很多关于命令行的东西了。
@@ -36,7 +34,7 @@
涵盖范围:
-- 这篇文章不仅能帮助刚接触命令行的新手,而且对具有经验的人也大有裨益。本文致力于做到*覆盖面广*(涉及所有重要的内容),*具体*(给出具体的最常用的例子),以及*简洁*(避免冗余的内容,或是可以在其他地方轻松查到的细枝末节)。在特定应用场景下,本文的内容属于基本功或者能帮助您节约大量的时间。
+- 这篇文章不仅能帮助刚接触命令行的新手,而且对具有经验的人也大有裨益。本文致力于做到*覆盖面广*(涉及所有重要的内容),_具体_(给出具体的最常用的例子),以及*简洁*(避免冗余的内容,或是可以在其他地方轻松查到的细枝末节)。在特定应用场景下,本文的内容属于基本功或者能帮助您节约大量的时间。
- 本文主要为 Linux 所写,但在[仅限 OS X 系统](#仅限-os-x-系统)章节和[仅限 Windows 系统](#仅限-windows-系统)章节中也包含有对应操作系统的内容。除去这两个章节外,其它的内容大部分均可在其他类 Unix 系统或 OS X,甚至 Cygwin 中得到应用。
- 本文主要关注于交互式 Bash,但也有很多技巧可以应用于其他 shell 和 Bash 脚本当中。
- 除去“标准的”Unix 命令,本文还包括了一些依赖于特定软件包的命令(前提是它们具有足够的价值)。
@@ -47,7 +45,6 @@
`pip` 或 `brew`(以及其它合适的包管理器)来安装依赖的程序。
- 遇到问题的话,请尝试使用 [Explainshell](http://explainshell.com/) 去获取相关命令、参数、管道等内容的解释。
-
## 基础
- 学习 Bash 的基础知识。具体地,在命令行中输入 `man bash` 并至少全文浏览一遍; 它理解起来很简单并且不冗长。其他的 shell 可能很好用,但 Bash 的功能已经足够强大并且到几乎总是可用的( 如果你*只*学习 zsh,fish 或其他的 shell 的话,在你自己的设备上会显得很方便,但过度依赖这些功能会给您带来不便,例如当你需要在服务器上工作时)。
@@ -74,33 +71,31 @@
- 学会使用 `apt-get`,`yum`,`dnf` 或 `pacman` (具体使用哪个取决于你使用的 Linux 发行版)来查找和安装软件包。并确保你的环境中有 `pip` 来安装基于 Python 的命令行工具 (接下来提到的部分程序使用 `pip` 来安装会很方便)。
-
## 日常使用
- 在 Bash 中,可以通过按 **Tab** 键实现自动补全参数,使用 **ctrl-r** 搜索命令行历史记录(按下按键之后,输入关键字便可以搜索,重复按下 **ctrl-r** 会向后查找匹配项,按下 **Enter** 键会执行当前匹配的命令,而按下右方向键会将匹配项放入当前行中,不会直接执行,以便做出修改)。
-- 在 Bash 中,可以按下 **ctrl-w** 删除你键入的最后一个单词,**ctrl-u** 可以删除行内光标所在位置之前的内容,**alt-b** 和 **alt-f** 可以以单词为单位移动光标,**ctrl-a** 可以将光标移至行首,**ctrl-e** 可以将光标移至行尾,**ctrl-k** 可以删除光标至行尾的所有内容,**ctrl-l** 可以清屏。键入 `man readline` 可以查看 Bash 中的默认快捷键。内容有很多,例如 **alt-.** 循环地移向前一个参数,而 **alt-*** 可以展开通配符。
+- 在 Bash 中,可以按下 **ctrl-w** 删除你键入的最后一个单词,**ctrl-u** 可以删除行内光标所在位置之前的内容,**alt-b** 和 **alt-f** 可以以单词为单位移动光标,**ctrl-a** 可以将光标移至行首,**ctrl-e** 可以将光标移至行尾,**ctrl-k** 可以删除光标至行尾的所有内容,**ctrl-l** 可以清屏。键入 `man readline` 可以查看 Bash 中的默认快捷键。内容有很多,例如 **alt-.** 循环地移向前一个参数,而 **alt-\*** 可以展开通配符。
+* 你喜欢的话,可以执行 `set -o vi` 来使用 vi 风格的快捷键,而执行 `set -o emacs` 可以把它改回来。
-- 你喜欢的话,可以执行 `set -o vi` 来使用 vi 风格的快捷键,而执行 `set -o emacs` 可以把它改回来。
+* 为了便于编辑长命令,在设置你的默认编辑器后(例如 `export EDITOR=vim`),**ctrl-x** **ctrl-e** 会打开一个编辑器来编辑当前输入的命令。在 vi 风格下快捷键则是 **escape-v**。
-- 为了便于编辑长命令,在设置你的默认编辑器后(例如 `export EDITOR=vim`),**ctrl-x** **ctrl-e** 会打开一个编辑器来编辑当前输入的命令。在 vi 风格下快捷键则是 **escape-v**。
+* 键入 `history` 查看命令行历史记录,再用 `!n`(`n` 是命令编号)就可以再次执行。其中有许多缩写,最有用的大概就是 `!$`, 它用于指代上次键入的参数,而 `!!` 可以指代上次键入的命令了(参考 man 页面中的“HISTORY EXPANSION”)。不过这些功能,你也可以通过快捷键 **ctrl-r** 和 **alt-.** 来实现。
-- 键入 `history` 查看命令行历史记录,再用 `!n`(`n` 是命令编号)就可以再次执行。其中有许多缩写,最有用的大概就是 `!$`, 它用于指代上次键入的参数,而 `!!` 可以指代上次键入的命令了(参考 man 页面中的“HISTORY EXPANSION”)。不过这些功能,你也可以通过快捷键 **ctrl-r** 和 **alt-.** 来实现。
+* `cd` 命令可以切换工作路径,输入 `cd \~` 可以进入 home 目录。要访问你的 home 目录中的文件,可以使用前缀 `\~`(例如 `\~/.bashrc`)。在 `sh` 脚本里则用环境变量 `$HOME` 指代 home 目录的路径。
-- `cd` 命令可以切换工作路径,输入 `cd \~` 可以进入 home 目录。要访问你的 home 目录中的文件,可以使用前缀 `\~`(例如 `\~/.bashrc`)。在 `sh` 脚本里则用环境变量 `$HOME` 指代 home 目录的路径。
+* 回到前一个工作路径:`cd -`。
-- 回到前一个工作路径:`cd -`。
+* 如果你输入命令的时候中途改了主意,按下 **alt-#** 在行首添加 `#` 把它当做注释再按下回车执行(或者依次按下 **ctrl-a**, **#**, **enter**)。这样做的话,之后借助命令行历史记录,你可以很方便恢复你刚才输入到一半的命令。
-- 如果你输入命令的时候中途改了主意,按下 **alt-#** 在行首添加 `#` 把它当做注释再按下回车执行(或者依次按下 **ctrl-a**, **#**, **enter**)。这样做的话,之后借助命令行历史记录,你可以很方便恢复你刚才输入到一半的命令。
+* 使用 `xargs` ( 或 `parallel`)。他们非常给力。注意到你可以控制每行参数个数(`-L`)和最大并行数(`-P`)。如果你不确定它们是否会按你想的那样工作,先使用 `xargs echo` 查看一下。此外,使用 `-I{}` 会很方便。例如:
-- 使用 `xargs` ( 或 `parallel`)。他们非常给力。注意到你可以控制每行参数个数(`-L`)和最大并行数(`-P`)。如果你不确定它们是否会按你想的那样工作,先使用 `xargs echo` 查看一下。此外,使用 `-I{}` 会很方便。例如:
```bash
find . -name '*.py' | xargs grep some_function
cat hosts | xargs -I{} ssh root@{} hostname
```
-
- `pstree -p` 以一种优雅的方式展示进程树。
- 使用 `pgrep` 和 `pkill` 根据名字查找进程或发送信号(`-f` 参数通常有用)。
@@ -126,28 +121,32 @@
- 当变量和文件名中包含空格的时候要格外小心。Bash 变量要用引号括起来,比如 `"$FOO"`。尽量使用 `-0` 或 `-print0` 选项以便用 NULL 来分隔文件名,例如 `locate -0 pattern | xargs -0 ls -al` 或 `find / -print0 -type d | xargs -0 ls -al`。如果 for 循环中循环访问的文件名含有空字符(空格、tab 等字符),只需用 `IFS=$'\n'` 把内部字段分隔符设为换行符。
- 在 Bash 脚本中,使用 `set -x` 去调试输出(或者使用它的变体 `set -v`,它会记录原始输入,包括多余的参数和注释)。尽可能地使用严格模式:使用 `set -e` 令脚本在发生错误时退出而不是继续运行;使用 `set -u` 来检查是否使用了未赋值的变量;试试 `set -o pipefail`,它可以监测管道中的错误。当牵扯到很多脚本时,使用 `trap` 来检测 ERR 和 EXIT。一个好的习惯是在脚本文件开头这样写,这会使它能够检测一些错误,并在错误发生时中断程序并输出信息:
+
```bash
set -euo pipefail
trap "echo 'error: Script failed: see failed command above'" ERR
```
- 在 Bash 脚本中,子 shell(使用括号 `(...)`)是一种组织参数的便捷方式。一个常见的例子是临时地移动工作路径,代码如下:
+
```bash
# do something in current dir
(cd /some/other/dir && other-command)
# continue in original dir
```
-- 在 Bash 中,变量有许多的扩展方式。`${name:?error message}` 用于检查变量是否存在。此外,当 Bash 脚本只需要一个参数时,可以使用这样的代码 `input_file=${1:?usage: $0 input_file}`。在变量为空时使用默认值:`${name:-default}`。如果你要在之前的例子中再加一个(可选的)参数,可以使用类似这样的代码 `output_file=${2:-logfile}`,如果省略了 $2,它的值就为空,于是 `output_file` 就会被设为 `logfile`。数学表达式:`i=$(( (i + 1) % 5 ))`。序列:`{1..10}`。截断字符串:`${var%suffix}` 和 `${var#prefix}`。例如,假设 `var=foo.pdf`,那么 `echo ${var%.pdf}.txt` 将输出 `foo.txt`。
+- 在 Bash 中,变量有许多的扩展方式。`${name:?error message}` 用于检查变量是否存在。此外,当 Bash 脚本只需要一个参数时,可以使用这样的代码 `input_file=${1:?usage: $0 input_file}`。在变量为空时使用默认值:`${name:-default}`。如果你要在之前的例子中再加一个(可选的)参数,可以使用类似这样的代码 `output_file=${2:-logfile}`,如果省略了 \$2,它的值就为空,于是 `output_file` 就会被设为 `logfile`。数学表达式:`i=$(( (i + 1) % 5 ))`。序列:`{1..10}`。截断字符串:`${var%suffix}` 和 `${var#prefix}`。例如,假设 `var=foo.pdf`,那么 `echo ${var%.pdf}.txt` 将输出 `foo.txt`。
- 使用括号扩展(`{`...`}`)来减少输入相似文本,并自动化文本组合。这在某些情况下会很有用,例如 `mv foo.{txt,pdf} some-dir`(同时移动两个文件),`cp somefile{,.bak}`(会被扩展成 `cp somefile somefile.bak`)或者 `mkdir -p test-{a,b,c}/subtest-{1,2,3}`(会被扩展成所有可能的组合,并创建一个目录树)。
- 通过使用 `<(some command)` 可以将输出视为文件。例如,对比本地文件 `/etc/hosts` 和一个远程文件:
+
```bash
diff /etc/hosts <(ssh somehost cat /etc/hosts)
```
- 编写脚本时,你可能会想要把代码都放在大括号里。缺少右括号的话,代码就会因为语法错误而无法执行。如果你的脚本是要放在网上分享供他人使用的,这样的写法就体现出它的好处了,因为这样可以防止下载不完全代码被执行。
+
```bash
{
# 在这里写代码
@@ -158,13 +157,14 @@
- 在 Bash 中,同时重定向标准输出和标准错误:`some-command >logfile 2>&1` 或者 `some-command &>logfile`。通常,为了保证命令不会在标准输入里残留一个未关闭的文件句柄捆绑在你当前所在的终端上,在命令后添加 `>> 2+3
5
```
-
## 文件及数据处理
- 在当前目录下通过文件名查找一个文件,使用类似于这样的命令:`find . -iname '*something*'`。在所有路径下通过文件名查找文件,使用 `locate something` (但注意到 `updatedb` 可能没有对最近新建的文件建立索引,所以你可能无法定位到这些未被索引的文件)。
@@ -222,7 +223,7 @@
- 要处理 Excel 或 CSV 文件的话,[csvkit](https://github.com/onyxfish/csvkit) 提供了 `in2csv`,`csvcut`,`csvjoin`,`csvgrep` 等方便易用的工具。
-- 当你要处理 Amazon S3 相关的工作的时候,[`s3cmd`](https://github.com/s3tools/s3cmd) 是一个很方便的工具而 [`s4cmd`](https://github.com/bloomreach/s4cmd) 的效率更高。Amazon 官方提供的 [`aws`](https://github.com/aws/aws-cli) 以及 [`saws`](https://github.com/donnemartin/saws) 是其他 AWS 相关工作的基础,值得学习。
+- 当你要处理 Amazon S3 相关的工作的时候,[`s3cmd`](https://github.com/s3tools/s3cmd) 是一个很方便的工具而 [`s4cmd`](https://github.com/bloomreach/s4cmd) 的效率更高。Amazon 官方提供的 [`aws`](https://github.com/aws/aws-cli) 以及 [`saws`](https://github.com/donnemartin/saws) 是其他 AWS 相关工作的基础,值得学习。
- 了解如何使用 `sort` 和 `uniq`,包括 uniq 的 `-u` 参数和 `-d` 参数,具体内容在后文单行脚本节中。另外可以了解一下 `comm`。
@@ -241,11 +242,13 @@
- 了解如何使用 `awk` 和 `sed` 来进行简单的数据处理。 参阅 [One-liners](#one-liners) 获取示例。
- 替换一个或多个文件中出现的字符串:
+
```bash
perl -pi.bak -e 's/old-string/new-string/g' my-files-*.txt
```
- 使用 [`repren`](https://github.com/jlevy/repren) 来批量重命名文件,或是在多个文件中搜索替换内容。(有些时候 `rename` 命令也可以批量重命名,但要注意,它在不同 Linux 发行版中的功能并不完全一样。)
+
```bash
# 将文件、目录和内容全部重命名 foo -> bar:
repren --full --preserve-case --from foo --to bar .
@@ -256,11 +259,12 @@
```
- 根据 man 页面的描述,`rsync` 是一个快速且非常灵活的文件复制工具。它闻名于设备之间的文件同步,但其实它在本地情况下也同样有用。在安全设置允许下,用 `rsync` 代替 `scp` 可以实现文件续传,而不用重新从头开始。它同时也是删除大量文件的[最快方法](https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html)之一:
+
```bash
mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
```
-- 若要在复制文件时获取当前进度,可使用 `pv`,[`pycp`](https://github.com/dmerejkowsky/pycp),[`progress`](https://github.com/Xfennec/progress),`rsync --progress`。若所执行的复制为block块拷贝,可以使用 `dd status=progress`。
+- 若要在复制文件时获取当前进度,可使用 `pv`,[`pycp`](https://github.com/dmerejkowsky/pycp),[`progress`](https://github.com/Xfennec/progress),`rsync --progress`。若所执行的复制为 block 块拷贝,可以使用 `dd status=progress`。
- 使用 `shuf` 可以以行为单位来打乱文件的内容或从一个文件中随机选取多行。
@@ -277,6 +281,7 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
- 制作二进制差分文件(Delta 压缩),使用 `xdelta3`。
- 使用 `iconv` 更改文本编码。需要更高级的功能,可以使用 `uconv`,它支持一些高级的 Unicode 功能。例如,这条命令移除了所有重音符号:
+
```bash
uconv -f utf-8 -t utf-8 -x '::Any-Lower; ::Any-NFD; [:Nonspacing Mark:] >; ::Any-NFC; ' < input.txt > output.txt
```
@@ -290,6 +295,7 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
- 文件属性可以通过 `chattr` 进行设置,它比文件权限更加底层。例如,为了保护文件不被意外删除,可以使用不可修改标记:`sudo chattr +i /critical/directory/or/file`
- 使用 `getfacl` 和 `setfacl` 以保存和恢复文件权限。例如:
+
```bash
getfacl -R /some/path > permissions.txt
setfacl --restore=permissions.txt
@@ -315,7 +321,7 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
- 用 [`ncdu`](https://dev.yorhel.nl/ncdu) 来查看磁盘使用情况,它比寻常的命令,如 `du -sh *`,更节省时间。
-- 查找正在使用带宽的套接字连接或进程,使用 [`iftop`](http://www.ex-parrot.com/\~pdw/iftop/) 或 [`nethogs`](https://github.com/raboof/nethogs)。
+- 查找正在使用带宽的套接字连接或进程,使用 [`iftop`](http://www.ex-parrot.com/~pdw/iftop/) 或 [`nethogs`](https://github.com/raboof/nethogs)。
- `ab` 工具(Apache 中自带)可以简单粗暴地检查 web 服务器的性能。对于更复杂的负载测试,使用 `siege`。
@@ -331,7 +337,7 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
- 当调试一些之前出现的问题的时候,[`sar`](http://sebastien.godard.pagesperso-orange.fr/) 非常有用。它展示了 cpu、内存以及网络等的历史数据。
-- 关于更深层次的系统分析以及性能分析,看看 `stap`([SystemTap](https://sourceware.org/systemtap/wiki)),[`perf`](https://en.wikipedia.org/wiki/Perf_(Linux)),以及[`sysdig`](https://github.com/draios/sysdig)。
+- 关于更深层次的系统分析以及性能分析,看看 `stap`([SystemTap](https://sourceware.org/systemtap/wiki)),[`perf`](),以及[`sysdig`](https://github.com/draios/sysdig)。
- 查看你当前使用的系统,使用 `uname`,`uname -a`(Unix/kernel 信息)或者 `lsb_release -a`(Linux 发行版信息)。
@@ -340,12 +346,12 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
- 如果你删除了一个文件,但通过 `du` 发现没有释放预期的磁盘空间,请检查文件是否被进程占用:
`lsof | grep deleted | grep "filename-of-my-big-file"`
-
## 单行脚本
一些命令组合的例子:
- 当你需要对文本文件做集合交、并、差运算时,`sort` 和 `uniq` 会是你的好帮手。具体例子请参照代码后面的,此处假设 `a` 与 `b` 是两内容不同的文件。这种方式效率很高,并且在小文件和上 G 的文件上都能运用(注意尽管在 `/tmp` 在一个小的根分区上时你可能需要 `-T` 参数,但是实际上 `sort` 并不被内存大小约束),参阅前文中关于 `LC_ALL` 和 `sort` 的 `-u` 参数的部分。
+
```bash
sort a b | uniq > c # c 是 a 并 b
sort a b | uniq -d > c # c 是 a 交 b
@@ -354,18 +360,20 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
- 使用 `grep . *`(每行都会附上文件名)或者 `head -100 *`(每个文件有一个标题)来阅读检查目录下所有文件的内容。这在检查一个充满配置文件的目录(如 `/sys`、`/proc`、`/etc`)时特别好用。
+* 计算文本文件第三列中所有数的和(可能比同等作用的 Python 代码快三倍且代码量少三倍):
-- 计算文本文件第三列中所有数的和(可能比同等作用的 Python 代码快三倍且代码量少三倍):
```bash
awk '{ x += $3 } END { print x }' myfile
```
- 如果你想在文件树上查看大小/日期,这可能看起来像递归版的 `ls -l` 但比 `ls -lR` 更易于理解:
+
```bash
find . -type f -ls
```
- 假设你有一个类似于 web 服务器日志文件的文本文件,并且一个确定的值只会出现在某些行上,假设一个 `acct_id` 参数在 URI 中。如果你想计算出每个 `acct_id` 值有多少次请求,使用如下代码:
+
```bash
egrep -o 'acct_id=[0-9]+' access.log | cut -d= -f2 | sort | uniq -c | sort -rn
```
@@ -373,6 +381,7 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
- 要持续监测文件改动,可以使用 `watch`,例如检查某个文件夹中文件的改变,可以用 `watch -d -n 2 'ls -rtlh | tail'`;或者在排查 WiFi 设置故障时要监测网络设置的更改,可以用 `watch -d -n 2 ifconfig`。
- 运行这个函数从这篇文档中随机获取一条技巧(解析 Markdown 文件并抽取项目):
+
```bash
function taocl() {
curl -s https://raw.githubusercontent.com/jlevy/the-art-of-command-line/master/README-zh.md|
@@ -514,7 +523,7 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
- [`sar`](http://sebastien.godard.pagesperso-orange.fr/):系统历史数据
-- [`iftop`](http://www.ex-parrot.com/\~pdw/iftop/) 或 [`nethogs`](https://github.com/raboof/nethogs):套接字及进程的网络利用情况
+- [`iftop`](http://www.ex-parrot.com/~pdw/iftop/) 或 [`nethogs`](https://github.com/raboof/nethogs):套接字及进程的网络利用情况
- `ss`:套接字数据
@@ -526,13 +535,12 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
- `lsblk`:列出块设备信息:以树形展示你的磁盘以及磁盘分区信息
-- `lshw`,`lscpu`,`lspci`,`lsusb` 和 `dmidecode`:查看硬件信息,包括 CPU、BIOS、RAID、显卡、USB设备等
+- `lshw`,`lscpu`,`lspci`,`lsusb` 和 `dmidecode`:查看硬件信息,包括 CPU、BIOS、RAID、显卡、USB 设备等
- `lsmod` 和 `modinfo`:列出内核模块,并显示其细节
- `fortune`,`ddate` 和 `sl`:额,这主要取决于你是否认为蒸汽火车和莫名其妙的名人名言是否“有用”
-
## 仅限 OS X 系统
以下是*仅限于* OS X 系统的技巧。
@@ -604,11 +612,10 @@ mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
## 免责声明
-除去特别小的工作,你编写的代码应当方便他人阅读。能力往往伴随着责任,你 *有能力* 在 Bash 中玩一些奇技淫巧并不意味着你应该去做!;)
-
+除去特别小的工作,你编写的代码应当方便他人阅读。能力往往伴随着责任,你 _有能力_ 在 Bash 中玩一些奇技淫巧并不意味着你应该去做!;)
## 授权条款
-
+
本文使用授权协议 [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)。
diff --git a/docs/linux/expect.md b/docs/linux/expect.md
new file mode 100644
index 00000000..24c7d39e
--- /dev/null
+++ b/docs/linux/expect.md
@@ -0,0 +1,180 @@
+# expect shell 脚本
+
+## expect 简介
+
+`expect` 是一个自动化交互套件,主要应用于执行命令和程序时,系统以交互形式要求输入指定字符串,实现交互通信。
+
+在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用 `expect`,则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行。这就是 `expect` 。
+
+expect 自动交互流程:
+
+1. spawn 启动指定进程
+2. expect 获取指定关键字
+3. send 向指定程序发送指定字符
+4. 执行完成退出
+
+## expect 安装
+
+### yum 安装
+
+执行命令:
+
+```shell
+yum -y install expect
+```
+
+### 手动安装
+
+expect 依赖 tcl,所以需要先安装 tcl:
+
+```shell
+wget https://nchc.dl.sourceforge.net/project/tcl/Tcl/8.6.9/tcl8.6.9-src.tar.gz
+tar xf tcl8.6.9-src.tar.gz
+cd tcl8.6.9/unix/
+./configure && make && sudo make install
+```
+
+再安装 expect:
+
+```shell
+wget https://nchc.dl.sourceforge.net/project/expect/Expect/5.45.4/expect5.45.4.tar.gz
+tar xf expect5.45.4.tar.gz
+cd ./expect5.45.4
+./configure && make && sudo make install
+```
+
+## expect 参数
+
+启用选项:
+
+- `-c` - 执行脚本前先执行的命令,可多次使用。
+- `-d` - debug 模式,可以在运行时输出一些诊断信息,与在脚本开始处使用 `exp_internal 1` 相似。
+- `-D` - 启用交换调式器,可设一整数参数。
+- `-f` - 从文件读取命令,仅用于使用 `#!` 时。如果文件名为 `-`,则从 stdin 读取(使用 `./-` 从文件名为-的文件读取)。
+- `-i` - 交互式输入命令,使用 `exit` 或 `EOF` 退出输入状态。
+- `--` - 标示选项结束(如果你需要传递与 `expect` 选项相似的参数给脚本时),可放到 `#!` 行: `#!/usr/bin/expect --` 。
+- `-v` - 显示 `expect` 版本信息。
+
+## expect 命令
+
+- `spawn` - 命令用来启动新的进程,`spawn`后的`send`和`expect`命令都是和使用`spawn`打开的进程进行交互。
+- `expect` - 获取匹配信息,匹配成功则执行 `expect` 后面的程序动作。
+ - `exp_continue` - 在 `expect` 中多次匹配就需要用到。
+- `send` - 命令接收一个字符串参数,并将该参数发送到进程。
+ - `send exp_send` - 用于发送指定的字符串信息。
+- `interact` - 命令用的其实不是很多,一般情况下使用`spawn`、`send`和`expect`命令就可以很好的完成我们的任务;但在一些特殊场合下还是需要使用`interact`命令的,`interact`命令主要用于退出自动化,进入人工交互。比如我们使用`spawn`、`send`和`expect`命令完成了 ftp 登陆主机,执行下载文件任务,但是我们希望在文件下载结束以后,仍然可以停留在 ftp 命令行状态,以便手动的执行后续命令,此时使用`interact`命令就可以很好的完成这个任务。
+- `send_user` - 用来打印输出 相当于 shell 中的 echo
+- `set` - 定义变量。
+ - `set timeout` - 设置超时时间。
+- `puts` - 输出变量。
+- `exit` - 退出 expect 脚本
+- `eof` - expect 执行结束,退出。
+
+## 示例场景
+
+远程登录
+
+(1)ssh 登录远程主机执行命令,执行方法 `expect 1.sh` 或者 `source 1.sh`
+
+```shell
+#!/usr/bin/expect
+
+spawn ssh saneri@192.168.56.103 df -Th
+expect "*password"
+send "123456\n"
+expect eof
+```
+
+(2)ssh 远程登录主机执行命令,在 shell 脚本中执行 expect 命令,执行方法 sh 2.sh、bash 2.sh 或./2.sh 都可以执行.
+
+```
+#!/bin/bash
+
+passwd='123456'
+
+/usr/bin/expect <<-EOF
+
+set time 30
+spawn ssh saneri@192.168.56.103 df -Th
+expect {
+"*yes/no" { send "yes\r"; exp_continue }
+"*password:" { send "$passwd\r" }
+}
+expect eof
+EOF
+```
+
+(3)expect 执行多条命令
+
+```
+#!/usr/bin/expect -f
+
+set timeout 10
+
+spawn sudo su - root
+expect "*password*"
+send "123456\r"
+expect "#*"
+send "ls\r"
+expect "#*"
+send "df -Th\r"
+send "exit\r"
+expect eof
+```
+
+(4)创建 ssh key,将 id_rsa 和 id_rsa.pub 文件分发到各台主机上面。
+
+```shell
+#!/bin/bash
+
+# 判断id_rsa密钥文件是否存在
+if [ ! -f ~/.ssh/id_rsa ];then
+ ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
+else
+ echo "id_rsa has created ..."
+fi
+
+#分发到各个节点,这里分发到host文件中的主机中.
+while read line
+ do
+ user=`echo $line | cut -d " " -f 2`
+ ip=`echo $line | cut -d " " -f 1`
+ passwd=`echo $line | cut -d " " -f 3`
+
+ expect < 环境:CentOS
+
+通过 `crontab` 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script 脚本。时间间隔的单位可以是分钟、小时、日、月、周及以上的任意组合。这个命令非常适合周期性的日志分析或数据备份等工作。
+
+## crond 服务
+
+Linux 通过 crond 服务来支持 crontab。
+
+### 检查 `crond` 服务
+
+使用 `systemctl list-unit-files` 命令确认 `crond` 服务是否已安装。
+
+```shell
+$ systemctl list-unit-files | grep crond
+crond.service enabled
+```
+
+如果为 enabled,表示服务正运行。
+
+### crond 服务命令
+
+开机自动启动 crond 服务:`chkconfig crond on`
+
+或者,按以下命令手动启动:
+
+```shell
+systemctl enable crond.service # 开启服务(开机自动启动服务)
+systemctl disable crond.service # 关闭服务(开机不会自动启动服务)
+systemctl start crond.service # 启动服务
+systemctl stop crond.service # 停止服务
+systemctl restart crond.service # 重启服务
+systemctl reload crond.service # 重新载入配置
+systemctl status crond.service # 查看服务状态
+```
+
+## crontab
+
+### crontab 命令
+
+crontab 命令格式如下:
+
+```shell
+crontab [-u user] file crontab [-u user] [ -e | -l | -r ]
+```
+
+说明:
+
+- `-u user`:用来设定某个用户的 crontab 服务;
+- `file`:file 是命令文件的名字,表示将 file 做为 crontab 的任务列表文件并载入 crontab。如果在命令行中没有指定这个文件,crontab 命令将接受标准输入(键盘)上键入的命令,并将它们载入 crontab。
+- `-e`:编辑某个用户的 crontab 文件内容。如果不指定用户,则表示编辑当前用户的 crontab 文件。
+- `-l`:显示某个用户的 crontab 文件内容,如果不指定用户,则表示显示当前用户的 crontab 文件内容。
+- `-r`:从/var/spool/cron 目录中删除某个用户的 crontab 文件,如果不指定用户,则默认删除当前用户的 crontab 文件。
+- `-i`:在删除用户的 crontab 文件时给确认提示。
+
+有两种方法写入定时任务:
+
+- 在命令行输入:`crontab -e` 然后添加相应的任务,存盘退出。
+- 直接编辑 `/etc/crontab` 文件,即 `vi /etc/crontab`,添加相应的任务。
+
+### crontab 文件
+
+crontab 要执行的定时任务都被保存在 `/etc/crontab` 文件中。
+
+crontab 的文件格式如下:
+
+
+
+#### 标准字段
+
+**逗号**用于分隔列表。例如,在第 5 个字段(星期几)中使用 `MON,WED,FRI` 表示周一、周三和周五。
+
+**连字符**定义范围。例如,`2000-2010` 表示 2000 年至 2010 年期间的每年,包括 2000 年和 2010 年。
+
+除非用反斜杠(\)转义,否则命令中的**百分号(%)**会被替换成换行符,第一个百分号后面的所有数据都会作为标准输入发送给命令。
+
+| 字段 | 是否必填 | 允许值 | 允许特殊字符 |
+| :----------- | :------- | :-------------- | :----------- |
+| Minutes | 是 | 0–59 | `*`,`-` |
+| Hours | 是 | 0–23 | `*`,`-` |
+| Day of month | 是 | 1–31 | `*`,`-` |
+| Month | 是 | 1–12 or JAN–DEC | `*`,`-` |
+| Day of week | 是 | 0–6 or SUN–SAT | `*`,`-` |
+
+`/etc/crontab` 文件示例:
+
+```shell
+SHELL=/bin/bash
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+MAILTO=root
+
+# For details see man 4 crontabs
+
+# Example of job definition:
+# .---------------- minute (0 - 59)
+# | .------------- hour (0 - 23)
+# | | .---------- day of month (1 - 31)
+# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
+# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
+# | | | | |
+# * * * * * user-name command to be executed
+
+# 每两个小时以root身份执行 /home/hello.sh 脚本
+0 */2 * * * root /home/hello.sh
+```
+
+### crontab 实例
+
+#### 实例 1:每 1 分钟执行一次 myCommand
+
+```shell
+* * * * * myCommand
+```
+
+#### 实例 2:每小时的第 3 和第 15 分钟执行
+
+```shell
+3,15 * * * * myCommand
+```
+
+#### 实例 3:在上午 8 点到 11 点的第 3 和第 15 分钟执行
+
+```shell
+3,15 8-11 * * * myCommand
+```
+
+#### 实例 4:每隔两天的上午 8 点到 11 点的第 3 和第 15 分钟执行
+
+```shell
+3,15 8-11 */2 * * myCommand
+```
+
+#### 实例 5:每周一上午 8 点到 11 点的第 3 和第 15 分钟执行
+
+```shell
+3,15 8-11 * * 1 myCommand
+```
+
+#### 实例 6:每晚的 21:30 重启 smb
+
+```shell
+30 21 * * * /etc/init.d/smb restart
+```
+
+#### 实例 7:每月 1、10、22 日的 4 : 45 重启 smb
+
+```shell
+45 4 1,10,22 * * /etc/init.d/smb restart
+```
+
+#### 实例 8:每周六、周日的 1 : 10 重启 smb
+
+```shell
+10 1 * * 6,0 /etc/init.d/smb restart
+```
+
+#### 实例 9:每天 18 : 00 至 23 : 00 之间每隔 30 分钟重启 smb
+
+```shell
+0,30 18-23 * * * /etc/init.d/smb restart
+```
+
+#### 实例 10:每星期六的晚上 11 : 00 pm 重启 smb
+
+```shell
+0 23 * * 6 /etc/init.d/smb restart
+```
+
+#### 实例 11:每一小时重启 smb
+
+```shell
+0 * * * * /etc/init.d/smb restart
+```
+
+#### 实例 12:晚上 11 点到早上 7 点之间,每隔一小时重启 smb
+
+```shell
+0 23-7 * * * /etc/init.d/smb restart
+```
+
+## 参考资料
+
+- **文章**
+ - [crontab 定时任务](https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/crontab.html)
+ - [linux 定时执行脚本](https://blog.csdn.net/z_yong_cool/article/details/79288397)
+- **在线工具**
+ - [https://tool.lu/crontab/](https://tool.lu/crontab/)
+ - [https://cron.qqe2.com/](https://cron.qqe2.com/)
diff --git a/docs/linux/ops/firewalld.md b/docs/linux/ops/firewalld.md
new file mode 100644
index 00000000..90fb7784
--- /dev/null
+++ b/docs/linux/ops/firewalld.md
@@ -0,0 +1,38 @@
+# 防火墙 - Firewalld
+
+## 一、firewalld 服务命令
+
+```shell
+systemctl enable firewalld.service # 开启服务(开机自动启动服务)
+systemctl disable firewalld.service # 关闭服务(开机不会自动启动服务)
+systemctl start firewalld.service # 启动服务
+systemctl stop firewalld.service # 停止服务
+systemctl restart firewalld.service # 重启服务
+systemctl reload firewalld.service # 重新载入配置
+systemctl status firewalld.service # 查看服务状态
+```
+
+## 二、firewall-cmd 命令
+
+`firewall-cmd` 命令用于配置防火墙。
+
+```shell
+firewall-cmd --version # 查看版本
+firewall-cmd --help # 查看帮助
+firewall-cmd --state # 显示状态
+firewall-cmd --reload # 更新防火墙规则
+firewall-cmd --get-active-zones # 查看区域信息
+firewall-cmd --get-zone-of-interface=eth0 # 查看指定接口所属区域
+firewall-cmd --panic-on # 拒绝所有包
+firewall-cmd --panic-off # 取消拒绝状态
+firewall-cmd --query-panic # 查看是否拒绝
+
+firewall-cmd --zone=public --list-ports # 查看所有打开的端口
+firewall-cmd --zone=public --query-port=80/tcp # 查看是否有开放的 80 TCP 端口
+firewall-cmd --zone=public --add-port=8080/tcp --permanent # 添加开放端口(--permanent永久生效,没有此参数重启后失效)
+firewall-cmd --zone=public --remove-port=80/tcp --permanent # 永久删除开放的 80 TCP 端口
+```
+
+## 参考资料
+
+- [CentOS7 使用 firewalld 打开关闭防火墙与端口](https://www.cnblogs.com/moxiaoan/p/5683743.html)
\ No newline at end of file
diff --git a/docs/linux/ops/iptables.md b/docs/linux/ops/iptables.md
new file mode 100644
index 00000000..4863c05b
--- /dev/null
+++ b/docs/linux/ops/iptables.md
@@ -0,0 +1,279 @@
+# Iptables 应用
+
+> _iptables_ 是一个配置 Linux 内核 [防火墙](https://wiki.archlinux.org/index.php/Firewall) 的命令行工具,是 [netfilter](https://en.wikipedia.org/wiki/Netfilter) 项目的一部分。 可以直接配置,也可以通过许多前端和图形界面配置。
+>
+> iptables 也经常代指该内核级防火墙。iptables 用于 [ipv4](https://en.wikipedia.org/wiki/Ipv4),_ip6tables_ 用于 [ipv6](https://en.wikipedia.org/wiki/Ipv6)。
+>
+> [nftables](https://wiki.archlinux.org/index.php/Nftables) 已经包含在 [Linux kernel 3.13](http://www.phoronix.com/scan.php?page=news_item&px=MTQ5MDU) 中,以后会取代 iptables 成为主要的 Linux 防火墙工具。
+>
+> 环境:CentOS7
+
+## 1. 简介
+
+**iptables 可以检测、修改、转发、重定向和丢弃 IPv4 数据包**。
+
+过滤 IPv4 数据包的代码已经内置于内核中,并且按照不同的目的被组织成 **表** 的集合。**表** 由一组预先定义的 **链** 组成,**链**包含遍历顺序规则。每一条规则包含一个谓词的潜在匹配和相应的动作(称为 **目标**),如果谓词为真,该动作会被执行。也就是说条件匹配。
+
+## 2. 安装 iptables
+
+(1)禁用 firewalld
+
+CentOS 7 上默认安装了 firewalld 作为防火墙,使用 iptables 建议关闭并禁用 firewalld。
+
+```bash
+systemctl stop firewalld
+systemctl disable firewalld
+```
+
+(2)安装 iptables
+
+```
+yum install -y iptables-services
+```
+
+(3)服务管理
+
+- 查看服务状态:`systemctl status iptables`
+- 启用服务:`systemctl enable iptables`
+- 禁用服务:`systemctl disable iptables`
+- 启动服务:`systemctl start iptables`
+- 重启服务:`systemctl restart iptables`
+- 关闭服务: `systemctl stop iptables`
+
+## 3. 命令
+
+基本语法:
+
+```
+iptables(选项)(参数)
+```
+
+基本选项说明:
+
+| 参数 | 作用 |
+| ----------- | ------------------------------------------------- |
+| -P | 设置默认策略:iptables -P INPUT (DROP |
+| -F | 清空规则链 |
+| -L | 查看规则链 |
+| -A | 在规则链的末尾加入新规则 |
+| -I | num 在规则链的头部加入新规则 |
+| -D | num 删除某一条规则 |
+| -s | 匹配来源地址 IP/MASK,加叹号"!"表示除这个 IP 外。 |
+| -d | 匹配目标地址 |
+| -i | 网卡名称 匹配从这块网卡流入的数据 |
+| -o | 网卡名称 匹配从这块网卡流出的数据 |
+| -p | 匹配协议,如 tcp,udp,icmp |
+| --dport num | 匹配目标端口号 |
+| --sport num | 匹配来源端口号 |
+
+顺序:
+
+```
+iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作
+```
+
+## 4. iptables 示例
+
+### 4.1. 清空当前的所有规则和计数
+
+```shell
+iptables -F # 清空所有的防火墙规则
+iptables -X # 删除用户自定义的空链
+iptables -Z # 清空计数
+```
+
+### 4.2. 配置允许 ssh 端口连接
+
+```shell
+iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT
+# 22为你的ssh端口, -s 192.168.1.0/24表示允许这个网段的机器来连接,其它网段的ip地址是登陆不了你的机器的。 -j ACCEPT表示接受这样的请求
+```
+
+### 4.3. 允许本地回环地址可以正常使用
+
+```shell
+iptables -A INPUT -i lo -j ACCEPT
+#本地圆环地址就是那个127.0.0.1,是本机上使用的,它进与出都设置为允许
+iptables -A OUTPUT -o lo -j ACCEPT
+```
+
+### 4.4. 设置默认的规则
+
+```shell
+iptables -P INPUT DROP # 配置默认的不让进
+iptables -P FORWARD DROP # 默认的不允许转发
+iptables -P OUTPUT ACCEPT # 默认的可以出去
+```
+
+### 4.5. 配置白名单
+
+```shell
+iptables -A INPUT -p all -s 192.168.1.0/24 -j ACCEPT # 允许机房内网机器可以访问
+iptables -A INPUT -p all -s 192.168.140.0/24 -j ACCEPT # 允许机房内网机器可以访问
+iptables -A INPUT -p tcp -s 183.121.3.7 --dport 3380 -j ACCEPT # 允许183.121.3.7访问本机的3380端口
+```
+
+### 4.6. 开启相应的服务端口
+
+```shell
+iptables -A INPUT -p tcp --dport 80 -j ACCEPT # 开启80端口,因为web对外都是这个端口
+iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT # 允许被ping
+iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 已经建立的连接得让它进来
+```
+
+### 4.7. 保存规则到配置文件中
+
+```shell
+cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak # 任何改动之前先备份,请保持这一优秀的习惯
+iptables-save > /etc/sysconfig/iptables
+cat /etc/sysconfig/iptables
+```
+
+### 4.8. 列出已设置的规则
+
+> iptables -L [-t 表名][链名]
+
+- 四个表名 `raw`,`nat`,`filter`,`mangle`
+- 五个规则链名 `INPUT`、`OUTPUT`、`FORWARD`、`PREROUTING`、`POSTROUTING`
+- filter 表包含`INPUT`、`OUTPUT`、`FORWARD`三个规则链
+
+```shell
+iptables -L -t nat # 列出 nat 上面的所有规则
+# ^ -t 参数指定,必须是 raw, nat,filter,mangle 中的一个
+iptables -L -t nat --line-numbers # 规则带编号
+iptables -L INPUT
+
+iptables -L -nv # 查看,这个列表看起来更详细
+```
+
+### 4.9. 清除已有规则
+
+```shell
+iptables -F INPUT # 清空指定链 INPUT 上面的所有规则
+iptables -X INPUT # 删除指定的链,这个链必须没有被其它任何规则引用,而且这条上必须没有任何规则。
+ # 如果没有指定链名,则会删除该表中所有非内置的链。
+iptables -Z INPUT # 把指定链,或者表中的所有链上的所有计数器清零。
+```
+
+### 4.10. 删除已添加的规则
+
+```shell
+# 添加一条规则
+iptables -A INPUT -s 192.168.1.5 -j DROP
+```
+
+将所有 iptables 以序号标记显示,执行:
+
+```shell
+iptables -L -n --line-numbers
+```
+
+比如要删除 INPUT 里序号为 8 的规则,执行:
+
+```shell
+iptables -D INPUT 8
+```
+
+### 4.11. 开放指定的端口
+
+```shell
+iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT #允许本地回环接口(即运行本机访问本机)
+iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT #允许已建立的或相关连的通行
+iptables -A OUTPUT -j ACCEPT #允许所有本机向外的访问
+iptables -A INPUT -p tcp --dport 22 -j ACCEPT #允许访问22端口
+iptables -A INPUT -p tcp --dport 80 -j ACCEPT #允许访问80端口
+iptables -A INPUT -p tcp --dport 21 -j ACCEPT #允许ftp服务的21端口
+iptables -A INPUT -p tcp --dport 20 -j ACCEPT #允许FTP服务的20端口
+iptables -A INPUT -j reject #禁止其他未允许的规则访问
+iptables -A FORWARD -j REJECT #禁止其他未允许的规则访问
+```
+
+### 4.12. 屏蔽 IP
+
+```shell
+iptables -A INPUT -p tcp -m tcp -s 192.168.0.8 -j DROP # 屏蔽恶意主机(比如,192.168.0.8
+iptables -I INPUT -s 123.45.6.7 -j DROP #屏蔽单个IP的命令
+iptables -I INPUT -s 123.0.0.0/8 -j DROP #封整个段即从123.0.0.1到123.255.255.254的命令
+iptables -I INPUT -s 124.45.0.0/16 -j DROP #封IP段即从123.45.0.1到123.45.255.254的命令
+iptables -I INPUT -s 123.45.6.0/24 -j DROP #封IP段即从123.45.6.1到123.45.6.254的命令是
+```
+
+### 4.13. 指定数据包出去的网络接口
+
+只对 OUTPUT,FORWARD,POSTROUTING 三个链起作用。
+
+```shell
+iptables -A FORWARD -o eth0
+```
+
+### 4.14. 查看已添加的规则
+
+```shell
+iptables -L -n -v
+Chain INPUT (policy DROP 48106 packets, 2690K bytes)
+ pkts bytes target prot opt in out source destination
+ 5075 589K ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
+ 191K 90M ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
+1499K 133M ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
+4364K 6351M ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
+ 6256 327K ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
+
+Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
+ pkts bytes target prot opt in out source destination
+
+Chain OUTPUT (policy ACCEPT 3382K packets, 1819M bytes)
+ pkts bytes target prot opt in out source destination
+ 5075 589K ACCEPT all -- * lo 0.0.0.0/0 0.0.0.0/0
+```
+
+### 4.15. 启动网络转发规则
+
+公网`210.14.67.7`让内网`192.168.188.0/24`上网
+
+```shell
+iptables -t nat -A POSTROUTING -s 192.168.188.0/24 -j SNAT --to-source 210.14.67.127
+```
+
+### 4.16. 端口映射
+
+本机的 2222 端口映射到内网 虚拟机的 22 端口
+
+```shell
+iptables -t nat -A PREROUTING -d 210.14.67.127 -p tcp --dport 2222 -j DNAT --to-dest 192.168.188.115:22
+```
+
+### 4.17. 字符串匹配
+
+比如,我们要过滤所有 TCP 连接中的字符串`test`,一旦出现它我们就终止这个连接,我们可以这么做:
+
+```shell
+iptables -A INPUT -p tcp -m string --algo kmp --string "test" -j REJECT --reject-with tcp-reset
+iptables -L
+
+# Chain INPUT (policy ACCEPT)
+# target prot opt source destination
+# REJECT tcp -- anywhere anywhere STRING match "test" ALGO name kmp TO 65535 reject-with tcp-reset
+#
+# Chain FORWARD (policy ACCEPT)
+# target prot opt source destination
+#
+# Chain OUTPUT (policy ACCEPT)
+# target prot opt source destination
+```
+
+### 4.18. 阻止 Windows 蠕虫的攻击
+
+```shell
+iptables -I INPUT -j DROP -p tcp -s 0.0.0.0/0 -m string --algo kmp --string "cmd.exe"
+```
+
+### 4.19. 防止 SYN 洪水攻击
+
+```shell
+iptables -A INPUT -p tcp --syn -m limit --limit 5/second -j ACCEPT
+```
+
+## 5. 参考资料
+
+- https://wiki.archlinux.org/index.php/iptables_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)
+- https://wangchujiang.com/linux-command/c/iptables.html
diff --git "a/docs/linux/ops/linux\345\205\270\345\236\213\350\277\220\347\273\264\345\272\224\347\224\250.md" "b/docs/linux/ops/linux\345\205\270\345\236\213\350\277\220\347\273\264\345\272\224\347\224\250.md"
deleted file mode 100644
index 1e5bd3ba..00000000
--- "a/docs/linux/ops/linux\345\205\270\345\236\213\350\277\220\347\273\264\345\272\224\347\224\250.md"
+++ /dev/null
@@ -1,303 +0,0 @@
----
-title: Linux 典型运维应用
-date: 2019-03-06
----
-
-# Linux 典型运维应用
-
-> :bulb: 如果没有特殊说明,本文的案例都是针对 Centos 发行版本。
-
-## 网络操作
-
-### 无法访问外网域名
-
-(1)在 hosts 中添加本机实际 IP 和本机实际域名的映射
-
-```bash
-echo "192.168.0.1 hostname" >> /etc/hosts
-```
-
-如果不知道本机域名,使用 `hostname` 命令查一下;如果不知道本机实际 IP,使用 `ifconfig` 查一下。
-
-(2)配置信赖的 DNS 服务器
-
-执行 `vi /etc/resolv.conf` ,添加以下内容:
-
-```bash
-nameserver 114.114.114.114
-nameserver 8.8.8.8
-```
-
-> 114.114.114.114 是国内老牌 DNS
->
-> 8.8.8.8 是 Google DNS
->
-> :point_right: 参考:[公共 DNS 哪家强](https://www.zhihu.com/question/32229915)
-
-(3)测试一下能否 ping 通 www.baidu.com
-
-### 开启、关闭防火墙
-
-firewalld 的基本使用
-
-```bash
-启动:systemctl start firewalld
-关闭:systemctl stop firewalld
-查看状态:systemctl status firewalld
-开机禁用:systemctl disable firewalld
-开机启用:systemctl enable firewalld
-```
-
-systemctl 是 CentOS7 的服务管理工具中主要的工具,它融合之前 service 和 chkconfig 的功能于一体。
-
-```
-启动一个服务:systemctl start firewalld.service
-关闭一个服务:systemctl stop firewalld.service
-重启一个服务:systemctl restart firewalld.service
-显示一个服务的状态:systemctl status firewalld.service
-在开机时启用一个服务:systemctl enable firewalld.service
-在开机时禁用一个服务:systemctl disable firewalld.service
-查看服务是否开机启动:systemctl is-enabled firewalld.service
-查看已启动的服务列表:systemctl list-unit-files|grep enabled
-查看启动失败的服务列表:systemctl --failed
-```
-
-配置 firewalld-cmd
-
-```
-查看版本:firewall-cmd --version
-查看帮助:firewall-cmd --help
-显示状态:firewall-cmd --state
-查看所有打开的端口:firewall-cmd --zone=public --list-ports
-更新防火墙规则:firewall-cmd --reload
-查看区域信息: firewall-cmd --get-active-zones
-查看指定接口所属区域:firewall-cmd --get-zone-of-interface=eth0
-拒绝所有包:firewall-cmd --panic-on
-取消拒绝状态:firewall-cmd --panic-off
-查看是否拒绝:firewall-cmd --query-panic
-```
-
-开启防火墙端口
-
-```
-添加:firewall-cmd --zone=public --add-port=80/tcp --permanent (--permanent永久生效,没有此参数重启后失效)
-重新载入:firewall-cmd --reload
-查看:firewall-cmd --zone= public --query-port=80/tcp
-删除:firewall-cmd --zone= public --remove-port=80/tcp --permanent
-```
-
-> :point_right: 参考:[CentOS7 使用 firewalld 打开关闭防火墙与端口](https://www.cnblogs.com/moxiaoan/p/5683743.html)
-
-## 系统维护
-
-### 使用 NTP 进行时间同步
-
-(1)先安装时钟同步工具 ntp
-
-```
-yum -y install ntp
-```
-
-ntp 的配置文件路径为: `/etc/ntp.conf`
-
-(2)启动 NTP 服务
-
-```bash
-systemctl start ntpd.service
-```
-
-(3)放开防火墙 123 端口
-
-NTP 服务的端口是 123,使用的是 udp 协议,所以 NTP 服务器的防火墙必须对外开放 udp 123 这个端口。
-
-```
-/sbin/iptables -A INPUT -p UDP -i eth0 -s 192.168.0.0/24 --dport 123 -j ACCEPT
-```
-
-(4)执行时间同步
-
-```
-/usr/sbin/ntpdate ntp.sjtu.edu.cn
-```
-
-ntp.sjtu.edu.cn 是上海交通大学 ntp 服务器。
-
-(5)自动定时同步时间
-
-执行如下命令,就可以在每天凌晨 3 点同步系统时间:
-
-```
-echo "* 3 * * * /usr/sbin/ntpdate ntp.sjtu.edu.cn" >> /etc/crontab
-systemctl restart crond.service
-```
-
-> :point_right: 参考:https://www.cnblogs.com/quchunhui/p/7658853.html
-
-## 自动化脚本
-
-### Linux 开机自启动脚本
-
-(1)在 `/etc/rc.local` 文件中添加命令
-
-如果不想将脚本粘来粘去,或创建链接,可以在 `/etc/rc.local` 文件中添加启动命令
-
-1. 先修改好脚本,使其所有模块都能在任意目录启动时正常执行;
-2. 再在 `/etc/rc.local` 的末尾添加一行以绝对路径启动脚本的行;
-
-例:
-
-执行 `vim /etc/rc.local` 命令,输入以下内容:
-
-```bash
-#!/bin/sh
-#
-# This script will be executed *after* all the other init scripts.
-# You can put your own initialization stuff in here if you don't
-# want to do the full Sys V style init stuff.
-
-touch /var/lock/subsys/local
-/opt/pjt_test/test.pl
-```
-
-(2)在 `/etc/rc.d/init.d` 目录下添加自启动脚本
-
-Linux 在 `/etc/rc.d/init.d` 下有很多的文件,每个文件都是可以看到内容的,其实都是一些 shell 脚本或者可执行二进制文件。
-
-Linux 开机的时候,会加载运行 `/etc/rc.d/init.d` 目录下的程序,因此我们可以把想要自动运行的脚本放到这个目录下即可。系统服务的启动就是通过这种方式实现的。
-
-(3)运行级别设置
-
-简单的说,运行级就是操作系统当前正在运行的功能级别。
-
-```
-不同的运行级定义如下:
-# 0 - 停机(千万不能把initdefault 设置为0 )
-# 1 - 单用户模式 进入方法#init s = init 1
-# 2 - 多用户,没有 NFS
-# 3 - 完全多用户模式(标准的运行级)
-# 4 - 没有用到
-# 5 - X11 多用户图形模式(xwindow)
-# 6 - 重新启动 (千万不要把initdefault 设置为6 )
-```
-
-这些级别在 `/etc/inittab` 文件里指定,这个文件是 init 程序寻找的主要文件,最先运行的服务是放在/etc/rc.d 目录下的文件。
-
-在 `/etc` 目录下面有这么几个目录值得注意:rcS.d rc0.d rc1.d ... rc6.d (0,1... 6 代表启动级别 0 代表停止,1 代表单用户模式,2-5 代表多用户模式,6 代表重启) 它们的作用就相当于 redhat 下的 rc.d ,你可以把脚本放到 rcS.d,然后修改文件名,给它一个启动序号,如: S88mysql
-
-不过,最好的办法是放到相应的启动级别下面。具体作法:
-
-(1)先把脚本 mysql 放到 /etc/init.d 目录下
-
-(2)查看当前系统的启动级别
-
-```bash
-$ runlevel
-N 3
-```
-
-(3)设定启动级别
-
-```
-# 98 为启动序号
-# 2 是系统的运行级别,可自己调整,注意不要忘了结尾的句点
-$ update-rc.d mysql start 98 2 .
-```
-
-现在我们到 /etc/rc2.d 下,就多了一个 S98mysql 这样的符号链接。
-
-(4)重启系统,验证设置是否有效。
-
-(5)移除符号链接
-
-当你需要移除这个符号连接时,方法有三种:
-
-1. 直接到 `/etc/rc2.d` 下删掉相应的链接,当然不是最好的方法;
-
-2. 推荐做法:`update-rc.d -f s10 remove`
-3. 如果 update-rc.d 命令你不熟悉,还可以试试看 rcconf 这个命令,也很方便。
-
-> :point_right: 参考:
->
-> - https://blog.csdn.net/linuxshine/article/details/50717272
-> - https://www.cnblogs.com/ssooking/p/6094740.html
-
-### 定时执行脚本
-
-(1)安装 crontab
-
-(2)开启 crontab 服务
-
-开机自动启动 crond 服务:`chkconfig crond on`
-
-或者,按以下命令手动启动:
-
-```bash
-# 启动服务
-systemctl start crond.service
-# 停止服务
-systemctl stop crond.service
-# 重启服务
-systemctl restart crond.service
-# 重新载入配置
-systemctl reload crond.service
-# 查看状态
-systemctl status crond.service
-```
-
-(3)设置需要执行的脚本
-
-有两种方法:
-
-- 在命令行输入:`crontab -e` 然后添加相应的任务,存盘退出。
-- 直接编辑 `/etc/crontab` 文件,即 `vi /etc/crontab`,添加相应的任务。
-
-示例:
-
-```bash
-SHELL=/bin/bash
-PATH=/sbin:/bin:/usr/sbin:/usr/bin
-MAILTO=root
-
-# For details see man 4 crontabs
-
-# Example of job definition:
-# .---------------- minute (0 - 59)
-# | .------------- hour (0 - 23)
-# | | .---------- day of month (1 - 31)
-# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
-# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
-# | | | | |
-# * * * * * user-name command to be executed
-
-# 每天早上3点时钟同步
-* 3 * * * /usr/sbin/ntpdate ntp.sjtu.edu.cn
-
-# 每两个小时以root身份执行 /home/hello.sh 脚本
-0 */2 * * * root /home/hello.sh
-```
-
-> :point_right: 参考:[linux 定时执行脚本](https://blog.csdn.net/z_yong_cool/article/details/79288397)
-
-## 配置
-
-### 设置 Linux 启动模式
-
-1. 停机(记得不要把 initdefault 配置为 0,因为这样会使 Linux 不能启动)
-2. 单用户模式,就像 Win9X 下的安全模式
-3. 多用户,但是没有 NFS
-4. 完全多用户模式,准则的运行级
-5. 通常不用,在一些特殊情况下可以用它来做一些事情
-6. X11,即进到 X-Window 系统
-7. 重新启动 (记得不要把 initdefault 配置为 6,因为这样会使 Linux 不断地重新启动)
-
-设置方法:
-
-```bash
-$ sed -i 's/id:5:initdefault:/id:3:initdefault:/' /etc/inittab
-```
-
-## 参考资料
-
-- [CentOS7 使用 firewalld 打开关闭防火墙与端口](https://www.cnblogs.com/moxiaoan/p/5683743.html)
-
-- [linux 定时执行脚本](https://blog.csdn.net/z_yong_cool/article/details/79288397)
diff --git a/docs/linux/ops/network-ops.md b/docs/linux/ops/network-ops.md
new file mode 100644
index 00000000..60792170
--- /dev/null
+++ b/docs/linux/ops/network-ops.md
@@ -0,0 +1,178 @@
+# Linux 典型运维应用
+
+> 💡 如果没有特殊说明,本文的案例都是针对 Centos 发行版本。
+
+## 网络操作
+
+### 无法访问外网域名
+
+(1)在 hosts 中添加本机实际 IP 和本机实际域名的映射
+
+```shell
+echo "192.168.0.1 hostname" >> /etc/hosts
+```
+
+如果不知道本机域名,使用 `hostname` 命令查一下;如果不知道本机实际 IP,使用 `ifconfig` 查一下。
+
+(2)配置信赖的 DNS 服务器
+
+执行 `vi /etc/resolv.conf` ,添加以下内容:
+
+```shell
+nameserver 114.114.114.114
+nameserver 8.8.8.8
+```
+
+> 114.114.114.114 是国内老牌 DNS
+>
+> 8.8.8.8 是 Google DNS
+>
+> :point_right: 参考:[公共 DNS 哪家强](https://www.zhihu.com/question/32229915)
+
+(3)测试一下能否 ping 通 www.baidu.com
+
+### 配置网卡
+
+使用 root 权限编辑 `/etc/sysconfig/network-scripts/ifcfg-eno16777736X` 文件
+
+参考以下进行配置:
+
+```properties
+TYPE=Ethernet # 网络类型:Ethernet以太网
+BOOTPROTO=none # 引导协议:自动获取、static静态、none不指定
+DEFROUTE=yes # 启动默认路由
+IPV4_FAILURE_FATAL=no # 不启用IPV4错误检测功能
+IPV6INIT=yes # 启用IPV6协议
+IPV6_AUTOCONF=yes # 自动配置IPV6地址
+IPV6_DEFROUTE=yes # 启用IPV6默认路由
+IPV6_FAILURE_FATAL=no # 不启用IPV6错误检测功能
+IPV6_PEERDNS=yes
+IPV6_PEERROUTES=yes
+IPV6_PRIVACY="no"
+
+NAME=eno16777736 # 网卡设备的别名(需要和文件名同名)
+UUID=90528772-9967-46da-b401-f82b64b4acbc # 网卡设备的UUID唯一标识号
+DEVICE=eno16777736 # 网卡的设备名称
+ONBOOT=yes # 开机自动激活网卡
+IPADDR=192.168.1.199 # 网卡的固定IP地址
+PREFIX=24 # 子网掩码
+GATEWAY=192.168.1.1 # 默认网关IP地址
+DNS1=8.8.8.8 # DNS域名解析服务器的IP地址
+```
+
+修改完后,执行 `systemctl restart network.service` 重启网卡服务。
+
+## 系统维护
+
+## 自动化脚本
+
+### Linux 开机自启动脚本
+
+(1)在 `/etc/rc.local` 文件中添加命令
+
+如果不想将脚本粘来粘去,或创建链接,可以在 `/etc/rc.local` 文件中添加启动命令
+
+1. 先修改好脚本,使其所有模块都能在任意目录启动时正常执行;
+2. 再在 `/etc/rc.local` 的末尾添加一行以绝对路径启动脚本的行;
+
+例:
+
+执行 `vim /etc/rc.local` 命令,输入以下内容:
+
+```shell
+#!/bin/sh
+#
+# This script will be executed *after* all the other init scripts.
+# You can put your own initialization stuff in here if you don't
+# want to do the full Sys V style init stuff.
+
+touch /var/lock/subsys/local
+/opt/pjt_test/test.pl
+```
+
+(2)在 `/etc/rc.d/init.d` 目录下添加自启动脚本
+
+Linux 在 `/etc/rc.d/init.d` 下有很多的文件,每个文件都是可以看到内容的,其实都是一些 shell 脚本或者可执行二进制文件。
+
+Linux 开机的时候,会加载运行 `/etc/rc.d/init.d` 目录下的程序,因此我们可以把想要自动运行的脚本放到这个目录下即可。系统服务的启动就是通过这种方式实现的。
+
+(3)运行级别设置
+
+简单的说,运行级就是操作系统当前正在运行的功能级别。
+
+```shell
+不同的运行级定义如下:
+# 0 - 停机(千万不能把initdefault 设置为0 )
+# 1 - 单用户模式 进入方法#init s = init 1
+# 2 - 多用户,没有 NFS
+# 3 - 完全多用户模式(标准的运行级)
+# 4 - 没有用到
+# 5 - X11 多用户图形模式(xwindow)
+# 6 - 重新启动 (千万不要把initdefault 设置为6 )
+```
+
+这些级别在 `/etc/inittab` 文件里指定,这个文件是 init 程序寻找的主要文件,最先运行的服务是放在/etc/rc.d 目录下的文件。
+
+在 `/etc` 目录下面有这么几个目录值得注意:rcS.d rc0.d rc1.d ... rc6.d (0,1... 6 代表启动级别 0 代表停止,1 代表单用户模式,2-5 代表多用户模式,6 代表重启) 它们的作用就相当于 redhat 下的 rc.d ,你可以把脚本放到 rcS.d,然后修改文件名,给它一个启动序号,如: S88mysql
+
+不过,最好的办法是放到相应的启动级别下面。具体作法:
+
+(1)先把脚本 mysql 放到 /etc/init.d 目录下
+
+(2)查看当前系统的启动级别
+
+```shell
+$ runlevel
+N 3
+```
+
+(3)设定启动级别
+
+```shell
+# 98 为启动序号
+# 2 是系统的运行级别,可自己调整,注意不要忘了结尾的句点
+$ update-rc.d mysql start 98 2 .
+```
+
+现在我们到 /etc/rc2.d 下,就多了一个 S98mysql 这样的符号链接。
+
+(4)重启系统,验证设置是否有效。
+
+(5)移除符号链接
+
+当你需要移除这个符号连接时,方法有三种:
+
+1. 直接到 `/etc/rc2.d` 下删掉相应的链接,当然不是最好的方法;
+
+2. 推荐做法:`update-rc.d -f s10 remove`
+3. 如果 update-rc.d 命令你不熟悉,还可以试试看 rcconf 这个命令,也很方便。
+
+> :point_right: 参考:
+>
+> - [linux 添加开机自启动脚本示例详解](https://blog.csdn.net/linuxshine/article/details/50717272)
+> - [linux 设置开机自启动](https://www.cnblogs.com/ssooking/p/6094740.html)
+
+### 定时执行脚本
+
+## 配置
+
+### 设置 Linux 启动模式
+
+1. 停机(记得不要把 initdefault 配置为 0,因为这样会使 Linux 不能启动)
+2. 单用户模式,就像 Win9X 下的安全模式
+3. 多用户,但是没有 NFS
+4. 完全多用户模式,准则的运行级
+5. 通常不用,在一些特殊情况下可以用它来做一些事情
+6. X11,即进到 X-Window 系统
+7. 重新启动 (记得不要把 initdefault 配置为 6,因为这样会使 Linux 不断地重新启动)
+
+设置方法:
+
+```shell
+sed -i 's/id:5:initdefault:/id:3:initdefault:/' /etc/inittab
+```
+
+## 参考资料
+
+- [CentOS7 使用 firewalld 打开关闭防火墙与端口](https://www.cnblogs.com/moxiaoan/p/5683743.html)
+- [linux 定时执行脚本](https://blog.csdn.net/z_yong_cool/article/details/79288397)
diff --git a/docs/linux/ops/ntp.md b/docs/linux/ops/ntp.md
new file mode 100644
index 00000000..9a72bdb7
--- /dev/null
+++ b/docs/linux/ops/ntp.md
@@ -0,0 +1,186 @@
+# 时间服务器 - NTP
+
+## 一、NTP 简介
+
+网络时间协议(英语:Network Time Protocol,缩写:NTP)是在数据网络潜伏时间可变的计算机系统之间通过分组交换进行时钟同步的一个网络协议,位于 OSI 模型的应用层。自 1985 年以来,NTP 是目前仍在使用的最古老的互联网协议之一。NTP 由特拉华大学的 David L. Mills(英语:David L. Mills)设计。
+
+**NTP 意图将所有参与计算机的协调世界时(UTC)时间同步到几毫秒的误差内**。
+
+NTP 要点:
+
+- 地球共有 24 个时区,而以格林威治时间 (GMT) 为标准时间;
+- 中国本地时间为 GMT +8 小时;
+- 最准确的时间为使用原子钟 (Atomic clock) 所计算的,例如 UTC (Coordinated Universal Time) 就是一例;
+- Linux 系统本来就有两种时间,一种是 Linux 以 `1970/01/01` 开始计数的系统时间,一种则是 BIOS 记载的硬件时间;
+- Linux 可以透过网络校时,最常见的网络校时为使用 NTP 服务器,这个服务启动在 `udp port 123`;
+- 时区档案主要放置于 `/usr/share/zoneinfo/` 目录下,而本地时区则参考 `/etc/localtime`;
+- NTP 服务器为一种阶层式的服务,所以 NTP 服务器本来就会与上层时间服务器作时间的同步化, 因此 `nptd` 与 `ntpdate` 两个指令不可同时使用;
+- NTP 服务器的联机状态可以使用 `ntpstat` 及 `ntpq -p` 来查询;
+- NTP 提供的客户端软件为 `ntpdate` 这个指令;
+- 在 Linux 下想要手动处理时间时,需以 `date` 设定时间后,以 `hwclock -w` 来写入 BIOS 所记录的时间。
+- NTP 服务器之间的时间误差不可超过 1000 秒,否则 NTP 服务会自动关闭。
+
+> 更多 NTP 详情可以参考:[鸟哥的 Linux 私房菜-- NTP 时间服务器](http://cn.linux.vbird.org/linux_server/0440ntp.php)
+
+## 二、ntpd 服务
+
+> 环境:CentOS
+
+### yum 安装
+
+CentOS 安装 NTP 很简单,执行以下命令即可:
+
+```shell
+yum -y install ntp
+```
+
+### ntpd 配置
+
+ntp 的配置文件路径为: `/etc/ntp.conf` ,参考配置:
+
+```shell
+# 1. 先处理权限方面的问题,包括放行上层服务器以及开放区网用户来源:
+# restrict default kod nomodify notrap nopeer noquery # 拒绝 IPv4 的用户
+# restrict -6 default kod nomodify notrap nopeer noquery # 拒绝 IPv6 的用户
+restrict default nomodify notrap nopeer noquery
+#restrict 192.168.100.0 mask 255.255.255.0 nomodify # 放行同局域网来源(根据网关和子网掩码决定)
+restrict 127.0.0.1 # 默认值,放行本机 IPv4 来源
+restrict ::1 # 默认值,放行本机 IPv6 来源
+
+# 2. 设定 NTP 主机来源
+# 注释掉默认 NTP 来源
+# server 0.centos.pool.ntp.org iburst
+# server 1.centos.pool.ntp.org iburst
+# server 2.centos.pool.ntp.org iburst
+# server 3.centos.pool.ntp.org iburst
+# 设置国内 NTP 来源
+server cn.pool.ntp.org prefer # 以这个主机为优先
+server ntp1.aliyun.com
+server ntp.sjtu.edu.cn
+
+# 3. 预设时间差异分析档案与暂不用到的 keys 等,不需要更改它:
+driftfile /var/lib/ntp/drift
+keys /etc/ntp/keys
+includefile /etc/ntp/crypto/pw
+```
+
+> 注意:如果更改配置,必须重启 NTP 服务(`systemctl restart ntpd`)才能生效。
+
+### 放开防火墙限制
+
+NTP 服务的端口是 `123`,使用的是 udp 协议,所以 NTP 服务器的防火墙必须对外开放 udp 123 这个端口。
+
+如果防火墙使用 **`iptables`**,执行以下命令:
+
+```shell
+iptables -A INPUT -p UDP -i eth0 -s 192.168.0.0/24 --dport 123 -j ACCEPT
+```
+
+如果防火墙使用 **`firewalld`**,执行以下命令:
+
+```shell
+firewall-cmd --zone=public --add-port=123/udp --permanent
+```
+
+### ntpd 服务命令
+
+```shell
+systemctl enable ntpd.service # 开启服务(开机自动启动服务)
+systemctl disable ntpd.service # 关闭服务(开机不会自动启动服务)
+systemctl start ntpd.service # 启动服务
+systemctl stop ntpd.service # 停止服务
+systemctl restart ntpd.service # 重启服务
+systemctl reload ntpd.service # 重新载入配置
+systemctl status ntpd.service # 查看服务状态
+```
+
+### 查看 ntp 服务状态
+
+#### 验证 NTP 服务正常工作
+
+执行 `ntpstat` 可以查看 ntp 服务器有无和上层 ntp 连通,,如果成功,可以看到类似以下的内容:
+
+```shell
+$ ntpstat
+synchronised to NTP server (5.79.108.34) at stratum 3
+ time correct to within 1129 ms
+ polling server every 64 s
+```
+
+#### 查看 ntp 服务器与上层 ntp 的状态
+
+```shell
+ntpq -p
+ remote refid st t when poll reach delay offset jitter
+==============================================================================
+*ntp1.ams1.nl.le 130.133.1.10 2 u 36 64 367 230.801 5.271 2.791
+ 120.25.115.20 10.137.53.7 2 u 33 64 377 25.930 15.908 3.168
+ time.cloudflare 10.21.8.251 3 u 31 64 367 251.109 16.976 3.264
+```
+
+## 三、ntpdate 命令
+
+> 注意:NTP 服务器为一种阶层式的服务,所以 NTP 服务器本来就会与上层时间服务器作时间的同步化, 因此 `nptd` 与 `ntpdate` 两个指令不可同时使用。
+
+### 手动执行时间同步
+
+`ntpdate` 命令是 NTP 的客户端软件,它可以用于请求时间同步。
+
+语法:
+
+```shell
+/usr/sbin/ntpdate
+```
+
+`ntp_server` 可以从 [国内 NTP 服务器](#国内 NTP 服务器) 中选择。
+
+示例:
+
+```shell
+$ ntpdate cn.pool.ntp.org
+11 Feb 10:47:12 ntpdate[30423]: step time server 84.16.73.33 offset -49.894774 sec
+```
+
+### 自动定时同步时间
+
+如果需要自动定时同步时间,可以利用 [Crontab](#crontab) 工具。本质就是用 crontab 定时执行一次手动时间同步命令 ntp。
+
+示例:执行如下命令,就可以在每天凌晨 3 点同步系统时间:
+
+```shell
+echo "0 3 * * * /usr/sbin/ntpdate cn.pool.ntp.org" >> /etc/crontab # 修改 crond 服务配置
+systemctl restart crond # 重启 crond 服务以生效
+```
+
+## 四、国内 NTP 服务器
+
+以下 NTP 服务器搜集自网络:
+
+```shell
+cn.pool.ntp.org # 最常用的国内NTP服务器,参考:https://www.ntppool.org/zh/use.html
+cn.ntp.org.cn # 中国
+edu.ntp.org.cn # 中国教育网
+ntp1.aliyun.com # 阿里云
+ntp2.aliyun.com # 阿里云
+ntp.sjtu.edu.cn # 上海交通大学
+s1a.time.edu.cn # 北京邮电大学
+s1b.time.edu.cn # 清华大学
+s1c.time.edu.cn # 北京大学
+s1d.time.edu.cn # 东南大学
+s1e.time.edu.cn # 清华大学
+s2a.time.edu.cn # 清华大学
+s2b.time.edu.cn # 清华大学
+s2c.time.edu.cn # 北京邮电大学
+s2d.time.edu.cn # 西南地区网络中心
+s2e.time.edu.cn # 西北地区网络中心
+s2f.time.edu.cn # 东北地区网络中心
+s2g.time.edu.cn # 华东南地区网络中心
+s2h.time.edu.cn # 四川大学网络管理中心
+s2j.time.edu.cn # 大连理工大学网络中心
+s2k.time.edu.cn # CERNET桂林主节点
+```
+
+## 参考资料
+
+- [鸟哥的 Linux 私房菜-- NTP 时间服务器](http://cn.linux.vbird.org/linux_server/0440ntp.php)
+- [Linux 配置 ntp 时间服务器](https://www.cnblogs.com/quchunhui/p/7658853.html)
diff --git a/docs/linux/ops/python.md b/docs/linux/ops/python.md
deleted file mode 100644
index 10b1bfd7..00000000
--- a/docs/linux/ops/python.md
+++ /dev/null
@@ -1,898 +0,0 @@
----
-title: Python
-date: 2018-06-28
-categories:
-- linux
-tags:
-- linux
-- python
----
-
-# Python
-
-
-
-- [解释器](#解释器)
-- [注释](#注释)
-- [数据类型](#数据类型)
-- [操作符](#操作符)
- - [算术运算符](#算术运算符)
- - [比较运算符](#比较运算符)
- - [赋值运算符](#赋值运算符)
- - [位运算符](#位运算符)
- - [逻辑运算符](#逻辑运算符)
- - [成员运算符](#成员运算符)
- - [身份运算符](#身份运算符)
- - [运算符优先级](#运算符优先级)
-- [控制语句](#控制语句)
- - [条件语句](#条件语句)
- - [循环语句](#循环语句)
-- [函数](#函数)
- - [函数变量作用域](#函数变量作用域)
- - [关键字参数](#关键字参数)
- - [可变参数列表](#可变参数列表)
- - [返回值](#返回值)
-- [异常](#异常)
- - [异常处理](#异常处理)
- - [抛出异常](#抛出异常)
- - [自定义异常](#自定义异常)
-- [面向对象](#面向对象)
- - [面向对象技术简介](#面向对象技术简介)
- - [类定义](#类定义)
- - [类对象](#类对象)
- - [类的方法](#类的方法)
- - [继承](#继承)
- - [多继承](#多继承)
- - [方法重写](#方法重写)
- - [类属性与方法](#类属性与方法)
-- [标准库概览](#标准库概览)
- - [操作系统接口](#操作系统接口)
- - [文件通配符](#文件通配符)
- - [命令行参数](#命令行参数)
- - [错误输出重定向和程序终止](#错误输出重定向和程序终止)
- - [字符串正则匹配](#字符串正则匹配)
- - [数学](#数学)
-
-
-
-# Python 编程
-
-## 解释器
-
-Linux/Unix 的系统上,Python 解释器通常被安装在 `/usr/local/bin/python3.4` 这样的有效路径(目录)里。
-
-我们可以将路径 `/usr/local/bin` 添加到您的 Linux/Unix 操作系统的环境变量中,这样您就可以通过 shell 终端输入下面的命令来启动 Python 。
-
-在 Linux/Unix 系统中,你可以在脚本顶部添加以下命令让 Python 脚本可以像 SHELL 脚本一样可直接执行:
-
-```python
-#! /usr/bin/env python3.4
-```
-
-## 注释
-
-Python 中的注释有三种形式:
-
-- 以 `#` 开头
-- 以 `'''` 开始,以 `'''` 结尾
-- 以 `"""` 开始,以 `"""` 结尾
-
-```python
-# 单行注释
-
-'''
-这是多行注释,用三个单引号
-这是多行注释,用三个单引号
-这是多行注释,用三个单引号
-'''
-
-"""
-这是多行注释,用三个双引号
-这是多行注释,用三个双引号
-这是多行注释,用三个双引号
-"""
-```
-
-## 数据类型
-
-Python3 中有六个标准的数据类型:
-
-- Numbers(数字)
-- String(字符串)
-- List(列表)
-- Tuple(元组)
-- Sets(集合)
-- Dictionaries(字典)
-
-## 操作符
-
-Python 语言支持以下类型的运算符:
-
-- 算术运算符
-
-- 比较(关系)运算符
-
-- 赋值运算符
-
-- 逻辑运算符
-
-- 位运算符
-
-- 成员运算符
-
-- 身份运算符
-
-- 运算符优先级
-
-### 算术运算符
-
-| 运算符 | 描述 | 实例 |
-| ------ | ----------------------------------------------- | --------------------------------------- |
-| + | 加 - 两个对象相加 | a + b 输出结果 31 |
-| - | 减 - 得到负数或是一个数减去另一个数 | a - b 输出结果 -11 |
-| \* | 乘 - 两个数相乘或是返回一个被重复若干次的字符串 | a \* b 输出结果 210 |
-| / | 除 - x 除以 y | b / a 输出结果 2.1 |
-| % | 取模 - 返回除法的余数 | b % a 输出结果 1 |
-| \*\* | 幂 - 返回 x 的 y 次幂 | a\*\*b 为 10 的 21 次方 |
-| // | 取整除 - 返回商的整数部分 | 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0 |
-
-### 比较运算符
-
-| 运算符 | 描述 | 实例 |
-| ------ | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
-| == | 等于 - 比较对象是否相等 | (a == b) 返回 False。 |
-| != | 不等于 - 比较两个对象是否不相等 | (a != b) 返回 True. |
-| > | 大于 - 返回 x 是否大于 y | (a > b) 返回 False。 |
-| < | 小于 - 返回 x 是否小于 y。所有比较运算符返回 1 表示真,返回 0 表示假。这分别与特殊的变量 True 和 False 等价。注意,这些变量名的大写。 | (a < b) 返回 True。 |
-| >= | 大于等于 - 返回 x 是否大于等于 y。 | (a >= b) 返回 False。 |
-| <= | 小于等于 - 返回 x 是否小于等于 y。 | (a <= b) 返回 True。 |
-
-### 赋值运算符
-
-| 运算符 | 描述 | 实例 |
-| ------ | ---------------- | ------------------------------------- |
-| = | 简单的赋值运算符 | c = a + b 将 a + b 的运算结果赋值为 c |
-| += | 加法赋值运算符 | c += a 等效于 c = c + a |
-| -= | 减法赋值运算符 | c -= a 等效于 c = c - a |
-| \*= | 乘法赋值运算符 | c _= a 等效于 c = c _ a |
-| /= | 除法赋值运算符 | c /= a 等效于 c = c / a |
-| %= | 取模赋值运算符 | c %= a 等效于 c = c % a |
-| \*\*= | 幂赋值运算符 | c **= a 等效于 c = c ** a |
-| //= | 取整除赋值运算符 | c //= a 等效于 c = c // a |
-
-### 位运算符
-
-| 运算符 | 描述 | 实例 |
-| ------ | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ |
-| & | 按位与运算符:参与运算的两个值,如果两个相应位都为 1,则该位的结果为 1,否则为 0 | (a & b) 输出结果 12 ,二进制解释: 0000 1100 |
-| \| | 按位或运算符:只要对应的二个二进位有一个为 1 时,结果位就为 1。 | (a \| b) 输出结果 61 ,二进制解释: 0011 1101 |
-| ^ | 按位异或运算符:当两对应的二进位相异时,结果为 1 | (a ^ b) 输出结果 49 ,二进制解释: 0011 0001 |
-| \~ | 按位取反运算符:对数据的每个二进制位取反,即把 1 变为 0,把 0 变为 1 | (\~a ) 输出结果 -61 ,二进制解释: 1100 0011, 在一个有符号二进制数的补码形式。 |
-| << | 左移动运算符:运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补 0。 | a << 2 输出结果 240 ,二进制解释: 1111 0000 |
-| >> | 右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数 | a >> 2 输出结果 15 ,二进制解释: 0000 1111 |
-
-### 逻辑运算符
-
-| 运算符 | 逻辑表达式 | 描述 | 实例 |
-| ------ | ---------- | ----------------------------------------------------------------------- | ----------------------- |
-| and | x and y | 布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 | (a and b) 返回 20。 |
-| or | x or y | 布尔"或" - 如果 x 是 True,它返回 x 的值,否则它返回 y 的计算值。 | (a or b) 返回 10。 |
-| not | not x | 布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 | not(a and b) 返回 False |
-
-### 成员运算符
-
-| 运算符 | 描述 | 实例 |
-| ------ | ------------------------------------------------------- | ------------------------------------------------- |
-| in | 如果在指定的序列中找到值返回 True,否则返回 False。 | x 在 y 序列中 , 如果 x 在 y 序列中返回 True。 |
-| not in | 如果在指定的序列中没有找到值返回 True,否则返回 False。 | x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。 |
-
-### 身份运算符
-
-| 运算符 | 描述 | 实例 |
-| ------ | ------------------------------------------- | ---------------------------------------------------------- |
-| is | is 是判断两个标识符是不是引用自一个对象 | x is y, 如果 id(x) 等于 id(y) , **is** 返回结果 1 |
-| is not | is not 是判断两个标识符是不是引用自不同对象 | x is not y, 如果 id(x) 不等于 id(y). **is not** 返回结果 1 |
-
-### 运算符优先级
-
-| 运算符 | 描述 |
-| --------------------------- | ------------------------------------------------------ |
-| \*\* | 指数 (最高优先级) |
-| \~ + - | 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@) |
-| \* / % // | 乘,除,取模和取整除 |
-| + - | 加法减法 |
-| >> << | 右移,左移运算符 |
-| & | 位 'AND' |
-| ^ \| | 位运算符 |
-| <= < > >= | 比较运算符 |
-| <> == != | 等于运算符 |
-| = %= /= //= -= += \*= \*\*= | 赋值运算符 |
-| is is not | 身份运算符 |
-| in not in | 成员运算符 |
-| not or and | 逻辑运算符 |
-
-## 控制语句
-
-### 条件语句
-
-```python
-if condition_1:
- statement_block_1
-elif condition_2:
- statement_block_2
-else:
- statement_block_3
-```
-
-### 循环语句
-
-#### while
-
-```python
-while 判断条件:
- statements
-```
-
-#### for
-
-```python
-for in :
-
-```
-
-#### range()
-
-```python
-for i in range(0, 10, 3) :
- print(i)
-```
-
-#### break 和 continue
-
-- break 语句可以跳出 for 和 while 的循环体。
-- continue 语句被用来告诉 Python 跳过当前循环块中的剩余语句,然后继续进行下一轮循环。
-
-#### pass
-
-pass 语句什么都不做。它只在语法上需要一条语句但程序不需要任何操作时使用.例如:
-
-```python
-while True:
- pass # 等待键盘中断 (Ctrl+C)
-```
-
-## 函数
-
-Python 定义函数使用 def 关键字,一般格式如下:
-
-```python
-def 函数名(参数列表):
- 函数体
-```
-
-### 函数变量作用域
-
-```python
-#!/usr/bin/env python3
-a = 4 # 全局变量
-
-def print_func1():
- a = 17 # 局部变量
- print("in print_func a = ", a)
-def print_func2():
- print("in print_func a = ", a)
-print_func1()
-print_func2()
-print("a = ", a)
-```
-
-以上实例运行结果如下:
-
-```python
-in print_func a = 17
-in print_func a = 4
-a = 4
-```
-
-### 关键字参数
-
-函数也可以使用 kwarg=value 的关键字参数形式被调用.例如,以下函数:
-
-```python
-def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
- print("-- This parrot wouldn't", action, end=' ')
- print("if you put", voltage, "volts through it.")
- print("-- Lovely plumage, the", type)
- print("-- It's", state, "!")
-```
-
-可以以下几种方式被调用:
-
-```python
-parrot(1000) # 1 positional argument
-parrot(voltage=1000) # 1 keyword argument
-parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
-parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
-parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
-parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
-```
-
-以下为错误调用方法:
-
-```
-parrot() # required argument missing
-parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
-parrot(110, voltage=220) # duplicate value for the same argument
-parrot(actor='John Cleese') # unknown keyword argument
-```
-
-### 可变参数列表
-
-最后,一个最不常用的选择是可以让函数调用可变个数的参数.这些参数被包装进一个元组(查看元组和序列).在这些可变个数的参数之前,可以有零到多个普通的参数:
-
-```python
-def arithmetic_mean(*args):
- sum = 0
- for x in args:
- sum += x
- return sum
-```
-
-### 返回值
-
-Python 的函数的返回值使用 return 语句,可以将函数作为一个值赋值给指定变量:
-
-```python
-def return_sum(x,y):
- c = x + y
- return c
-```
-
-## 异常
-
-### 异常处理
-
-try 语句按照如下方式工作;
-
-- 首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句)
-- 如果没有异常发生,忽略 except 子句,try 子句执行后结束。
-- 如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。最后执行 try 语句之后的代码。
-- 如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。
-- 不管 try 子句里面有没有发生异常,finally 子句都会执行。
-
-```python
-import sys
-
-try:
- f = open('myfile.txt')
- s = f.readline()
- i = int(s.strip())
-except OSError as err:
- print("OS error: {0}".format(err))
-except ValueError:
- print("Could not convert data to an integer.")
-except:
- print("Unexpected error:", sys.exc_info()[0])
- raise
-finally:
- # 清理行为
-```
-
-### 抛出异常
-
-Python 使用 raise 语句抛出一个指定的异常。例如:
-
-```python
->>> raise NameError('HiThere')
-Traceback (most recent call last):
- File "", line 1, in ?
-NameError: HiThere
-```
-
-### 自定义异常
-
-可以通过创建一个新的 exception 类来拥有自己的异常。异常应该继承自 Exception 类,或者直接继承,或者间接继承。
-
-当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类:
-
-```python
-class Error(Exception):
- """Base class for exceptions in this module."""
- pass
-
-class InputError(Error):
- """Exception raised for errors in the input.
-
- Attributes:
- expression -- input expression in which the error occurred
- message -- explanation of the error
- """
-
- def __init__(self, expression, message):
- self.expression = expression
- self.message = message
-
-class TransitionError(Error):
- """Raised when an operation attempts a state transition that's not
- allowed.
-
- Attributes:
- previous -- state at beginning of transition
- next -- attempted new state
- message -- explanation of why the specific transition is not allowed
- """
-
- def __init__(self, previous, next, message):
- self.previous = previous
- self.next = next
- self.message = message
-```
-
-大多数的异常的名字都以"Error"结尾,就跟标准的异常命名一样。
-
-## 面向对象
-
-### 面向对象技术简介
-
-- **类(Class):** 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
-
-- **类变量:**类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
-
-- **数据成员:**类变量或者实例变量用于处理类及其实例对象的相关的数据。
-
-- **方法重写:**如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
-
-- **实例变量:**定义在方法中的变量,只作用于当前实例的类。
-
-- **继承:**即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个 Dog 类型的对象派生自 Animal 类,这是模拟"是一个(is-a)"关系(例图,Dog 是一个 Animal)。
-
-- **实例化:**创建一个类的实例,类的具体对象。
-
-- **方法:**类中定义的函数。
-
-- **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
-
-### 类定义
-
-语法格式如下:
-
-```python
-class ClassName:
-
- .
- .
- .
-
-```
-
-类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。
-
-### 类对象
-
-类对象支持两种操作:属性引用和实例化。
-
-属性引用使用和 Python 中所有的属性引用一样的标准语法:**obj.name**。
-
-类对象创建后,类命名空间中所有的命名都是有效属性名。所以如果类定义是这样:
-
-```python
-#!/usr/bin/python3
-
-class MyClass:
- """一个简单的类实例"""
- i = 12345
- def f(self):
- return 'hello world'
-
-# 实例化类
-x = MyClass()
-
-# 访问类的属性和方法
-print("MyClass 类的属性 i 为:", x.i)
-print("MyClass 类的方法 f 输出为:", x.f())
-```
-
-实例化类:
-
-```python
-# 实例化类
-x = MyClass()
-# 访问类的属性和方法
-```
-
-以上创建了一个新的类实例并将该对象赋给局部变量 x,x 为空的对象。
-
-执行以上程序输出结果为:
-
-```
-MyClass 类的属性 i 为: 12345
-MyClass 类的方法 f 输出为: hello world
-```
-
-很多类都倾向于将对象创建为有初始状态的。因此类可能会定义一个名为 **init**() 的特殊方法(构造方法),像下面这样:
-
-```python
-def __init__(self):
- self.data = []
-```
-
-类定义了 **init**() 方法的话,类的实例化操作会自动调用 **init**() 方法。所以在下例中,可以这样创建一个新的实例:
-
-```python
-x = MyClass()
-```
-
-当然, **init**() 方法可以有参数,参数通过 **init**() 传递到类的实例化操作上。例如:
-
-```python
->>> class Complex:
-... def __init__(self, realpart, imagpart):
-... self.r = realpart
-... self.i = imagpart
-...
->>> x = Complex(3.0, -4.5)
->>> x.r, x.i
-(3.0, -4.5)
-```
-
-### 类的方法
-
-在类地内部,使用 def 关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数:
-
-```python
-#!/usr/bin/python3
-
-#类定义
-class people:
- #定义基本属性
- name = ''
- age = 0
- #定义私有属性,私有属性在类外部无法直接进行访问
- __weight = 0
- #定义构造方法
- def __init__(self,n,a,w):
- self.name = n
- self.age = a
- self.__weight = w
- def speak(self):
- print("%s 说: 我 %d 岁。" %(self.name,self.age))
-
-# 实例化类
-p = people('W3Cschool',10,30)
-p.speak()
-```
-
-执行以上程序输出结果为:
-
-```
-W3Cschool 说: 我 10 岁。
-```
-
-### 继承
-
-Python 同样支持类的继承,如果一种语言不支持继承就,类就没有什么意义。派生类的定义如下所示:
-
-```python
-class DerivedClassName(BaseClassName1):
-
- .
- .
- .
-
-```
-
-需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时未指定,python 从左至右搜索 即方法在子类中未找到时,从左到右查找基类中是否包含方法。
-
-BaseClassName(示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:
-
-```
-class DerivedClassName(modname.BaseClassName):
-```
-
-**实例**
-
-```python
-#!/usr/bin/python3
-
-#类定义
-class people:
- #定义基本属性
- name = ''
- age = 0
- #定义私有属性,私有属性在类外部无法直接进行访问
- __weight = 0
- #定义构造方法
- def __init__(self,n,a,w):
- self.name = n
- self.age = a
- self.__weight = w
- def speak(self):
- print("%s 说: 我 %d 岁。" %(self.name,self.age))
-
-#单继承示例
-class student(people):
- grade = ''
- def __init__(self,n,a,w,g):
- #调用父类的构函
- people.__init__(self,n,a,w)
- self.grade = g
- #覆写父类的方法
- def speak(self):
- print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
-
-
-
-s = student('ken',10,60,3)
-s.speak()
-```
-
-执行以上程序输出结果为:
-
-```
-ken 说: 我 10 岁了,我在读 3 年级
-```
-
-### 多继承
-
-Python 同样有限的支持多继承形式。多继承的类定义形如下例:
-
-```python
-class DerivedClassName(Base1, Base2, Base3):
-
- .
- .
- .
-
-```
-
-需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python 从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。
-
-```python
-#!/usr/bin/python3
-
-#类定义
-class people:
- #定义基本属性
- name = ''
- age = 0
- #定义私有属性,私有属性在类外部无法直接进行访问
- __weight = 0
- #定义构造方法
- def __init__(self,n,a,w):
- self.name = n
- self.age = a
- self.__weight = w
- def speak(self):
- print("%s 说: 我 %d 岁。" %(self.name,self.age))
-
-#单继承示例
-class student(people):
- grade = ''
- def __init__(self,n,a,w,g):
- #调用父类的构函
- people.__init__(self,n,a,w)
- self.grade = g
- #覆写父类的方法
- def speak(self):
- print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
-
-#另一个类,多重继承之前的准备
-class speaker():
- topic = ''
- name = ''
- def __init__(self,n,t):
- self.name = n
- self.topic = t
- def speak(self):
- print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))
-
-#多重继承
-class sample(speaker,student):
- a =''
- def __init__(self,n,a,w,g,t):
- student.__init__(self,n,a,w,g)
- speaker.__init__(self,n,t)
-
-test = sample("Tim",25,80,4,"Python")
-test.speak() #方法名同,默认调用的是在括号中排前地父类的方法
-```
-
-执行以上程序输出结果为:
-
-```
-我叫 Tim,我是一个演说家,我演讲的主题是 Python
-```
-
-### 方法重写
-
-如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法,实例如下:
-
-```python
-#!/usr/bin/python3
-
-class Parent: # 定义父类
- def myMethod(self):
- print ('调用父类方法')
-
-class Child(Parent): # 定义子类
- def myMethod(self):
- print ('调用子类方法')
-
-c = Child() # 子类实例
-c.myMethod() # 子类调用重写方法
-```
-
-执行以上程序输出结果为:
-
-```
-调用子类方法
-```
-
-### 类属性与方法
-
-#### 类的私有属性
-
-**\_\_private_attrs**:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时**self.\_\_private_attrs**。
-
-#### 类的方法
-
-在类地内部,使用 def 关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数
-
-#### 类的私有方法
-
-**\_\_private_method**:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用 **slef.\_\_private_methods**。
-
-实例如下:
-
-```python
-#!/usr/bin/python3
-
-class JustCounter:
- __secretCount = 0 # 私有变量
- publicCount = 0 # 公开变量
-
- def count(self):
- self.__secretCount += 1
- self.publicCount += 1
- print (self.__secretCount)
-
-counter = JustCounter()
-counter.count()
-counter.count()
-print (counter.publicCount)
-print (counter.__secretCount) # 报错,实例不能访问私有变量
-```
-
-执行以上程序输出结果为:
-
-```
-1
-2
-2
-Traceback (most recent call last):
- File "test.py", line 16, in
- print (counter.__secretCount) # 报错,实例不能访问私有变量
-AttributeError: 'JustCounter' object has no attribute '__secretCount'
-```
-
-#### 类的专有方法:
-
-- \***\*init** :\*\* 构造函数,在生成对象时调用
-- \***\*del** :\*\* 析构函数,释放对象时使用
-- \***\*repr** :\*\* 打印,转换
-- \***\*setitem** :\*\* 按照索引赋值
-- \***\*getitem**:\*\* 按照索引获取值
-- \***\*len**:\*\* 获得长度
-- \***\*cmp**:\*\* 比较运算
-- \***\*call**:\*\* 函数调用
-- \***\*add**:\*\* 加运算
-- \***\*sub**:\*\* 减运算
-- \***\*mul**:\*\* 乘运算
-- \***\*div**:\*\* 除运算
-- \***\*mod**:\*\* 求余运算
-- \***\*pow**:\*\* 乘方
-
-#### 运算符重载
-
-Python 同样支持运算符重载,我么可以对类的专有方法进行重载,实例如下:
-
-```python
-#!/usr/bin/python3
-
-class Vector:
- def __init__(self, a, b):
- self.a = a
- self.b = b
-
- def __str__(self):
- return 'Vector (%d, %d)' % (self.a, self.b)
-
- def __add__(self,other):
- return Vector(self.a + other.a, self.b + other.b)
-
-v1 = Vector(2,10)
-v2 = Vector(5,-2)
-print (v1 + v2)
-```
-
-以上代码执行结果如下所示:
-
-```
-Vector(7,8)
-```
-
-## 标准库概览
-
-### 操作系统接口
-
-os 模块提供了不少与操作系统相关联的函数。
-
-```python
->>> import os
->>> os.getcwd() # 返回当前的工作目录
-'C:\\Python34'
->>> os.chdir('/server/accesslogs') # 修改当前的工作目录
->>> os.system('mkdir today') # 执行系统命令 mkdir
-0
-```
-
-### 文件通配符
-
-glob 模块提供了一个函数用于从目录通配符搜索中生成文件列表:
-
-```python
->>> import glob
->>> glob.glob('*.py')
-['primes.py', 'random.py', 'quote.py']
-```
-
-### 命令行参数
-
-通用工具脚本经常调用命令行参数。这些命令行参数以链表形式存储于 sys 模块的 argv 变量。例如在命令行中执行 `python demo.py one two three` 后可以得到以下输出结果:
-
-```python
->>> import sys
->>> print(sys.argv)
-['demo.py', 'one', 'two', 'three']
-```
-
-### 错误输出重定向和程序终止
-
-sys 还有 stdin,stdout 和 stderr 属性,即使在 stdout 被重定向时,后者也可以用于显示警告和错误信息。
-
-```python
->>> sys.stderr.write('Warning, log file not found starting a new one\n')
-Warning, log file not found starting a new one
-```
-
-### 字符串正则匹配
-
-re 模块为高级字符串处理提供了正则表达式工具。对于复杂的匹配和处理,正则表达式提供了简洁、优化的解决方案:
-
-```python
->>> import re
->>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
-['foot', 'fell', 'fastest']
->>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
-'cat in the hat'
-```
-
-### 数学
-
-math 模块为浮点运算提供了对底层 C 函数库的访问:
-
-```python
->>> import math
->>> math.cos(math.pi / 4)
-0.70710678118654757
->>> math.log(1024, 2)
-10.0
-```
-
-# 资料
-
-- https://github.com/vinta/awesome-python - 资源大全
-- https://github.com/jobbole/awesome-python-cn - 资源大全
-- https://github.com/scrapy/scrapy - python 爬虫框架
-- https://github.com/faif/python-patterns - python 设计模式
-- https://github.com/kennethreitz/python-guide - python 最佳实践
diff --git "a/docs/linux/ops/samba\344\275\277\347\224\250\350\257\246\350\247\243.md" b/docs/linux/ops/samba.md
similarity index 92%
rename from "docs/linux/ops/samba\344\275\277\347\224\250\350\257\246\350\247\243.md"
rename to docs/linux/ops/samba.md
index cab94cf6..19fe6d9f 100644
--- "a/docs/linux/ops/samba\344\275\277\347\224\250\350\257\246\350\247\243.md"
+++ b/docs/linux/ops/samba.md
@@ -1,14 +1,4 @@
----
-title: samba 使用详解
-date: 2018-09-28
-categories:
- - linux
-tags:
- - linux
- - windows
----
-
-# samba 使用详解
+# Samba 应用
> samba 是在 Linux 和 UNIX 系统上实现 SMB 协议的一个免费软件。
>
@@ -16,28 +6,6 @@ tags:
>
> 关键词:`samba`, `selinux`
-
-
-- [1. 安装配置 samba](#1-安装配置-samba)
- - [1.1. 查看是否已经安装 samba](#11-查看是否已经安装-samba)
- - [1.2. 安装 samba 工具](#12-安装-samba-工具)
- - [1.3. 配置 samba](#13-配置-samba)
- - [1.4. 创建 samba 用户](#14-创建-samba-用户)
- - [1.5. 启动 samba 服务](#15-启动-samba-服务)
- - [1.6. 为 samba 添加防火墙规则](#16-为-samba-添加防火墙规则)
- - [1.7. 测试 samba 服务](#17-测试-samba-服务)
- - [1.8. 访问 samba 服务共享的目录](#18-访问-samba-服务共享的目录)
-- [2. 配置详解](#2-配置详解)
- - [2.1. samba 默认配置](#21-samba-默认配置)
- - [2.2. 全局参数 [global]](#22-全局参数-global)
- - [2.3. 共享参数 [共享名]](#23-共享参数-共享名)
-- [3. 常见问题](#3-常见问题)
- - [3.1. 你可能没有权限访问网络资源](#31-你可能没有权限访问网络资源)
- - [3.2. window 下对 samba 的清理操作](#32-window-下对-samba-的清理操作)
-- [4. 参考资料](#4-参考资料)
-
-
-
## 1. 安装配置 samba
本文将以一个完整的示例来展示如何配置 samba 来实现 Linux 和 Windows 的文件共享。
@@ -181,7 +149,7 @@ Windows:
访问:`\\<你的ip>\<你的共享路径>` :
-
+
Mac:
diff --git a/docs/linux/ops/shell.md b/docs/linux/ops/shell.md
deleted file mode 100644
index 43cfd6c3..00000000
--- a/docs/linux/ops/shell.md
+++ /dev/null
@@ -1,1689 +0,0 @@
-# 一篇文章让你彻底掌握 shell 语言
-
-> 由于 bash 是 Linux 标准默认的 shell 解释器,可以说 bash 是 shell 编程的基础。
->
-> 本文主要介绍 bash 的语法,对于 linux 指令不做任何介绍。
->
-> :notebook: 本文已归档到:「[blog](https://github.com/dunwu/blog)」
-> :keyboard: 本文的源码已归档到 [linux-tutorial](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos)
-
-```
-███████╗██╗ ██╗███████╗██╗ ██╗
-██╔════╝██║ ██║██╔════╝██║ ██║
-███████╗███████║█████╗ ██║ ██║
-╚════██║██╔══██║██╔══╝ ██║ ██║
-███████║██║ ██║███████╗███████╗███████╗
-```
-
-
-
-- [1. 简介](#1-简介)
- - [1.1. 什么是 shell](#11-什么是-shell)
- - [1.2. 什么是 shell 脚本](#12-什么是-shell-脚本)
- - [1.3. Shell 环境](#13-shell-环境)
- - [1.4. 模式](#14-模式)
-- [2. 基本语法](#2-基本语法)
- - [2.1. 解释器](#21-解释器)
- - [2.2. 注释](#22-注释)
- - [2.3. echo](#23-echo)
- - [2.4. printf](#24-printf)
-- [3. 变量](#3-变量)
- - [3.1. 变量命名原则](#31-变量命名原则)
- - [3.2. 声明变量](#32-声明变量)
- - [3.3. 只读变量](#33-只读变量)
- - [3.4. 删除变量](#34-删除变量)
- - [3.5. 变量类型](#35-变量类型)
- - [3.6. 变量示例源码](#36-变量示例源码)
-- [4. 字符串](#4-字符串)
- - [4.1. 单引号和双引号](#41-单引号和双引号)
- - [4.2. 拼接字符串](#42-拼接字符串)
- - [4.3. 获取字符串长度](#43-获取字符串长度)
- - [4.4. 截取子字符串](#44-截取子字符串)
- - [4.5. 查找子字符串](#45-查找子字符串)
- - [4.6. 字符串示例源码](#46-字符串示例源码)
-- [5. 数组](#5-数组)
- - [5.1. 创建数组](#51-创建数组)
- - [5.2. 访问数组元素](#52-访问数组元素)
- - [5.3. 访问数组长度](#53-访问数组长度)
- - [5.4. 向数组中添加元素](#54-向数组中添加元素)
- - [5.5. 从数组中删除元素](#55-从数组中删除元素)
- - [5.6. 数组示例源码](#56-数组示例源码)
-- [6. 运算符](#6-运算符)
- - [6.1. 算术运算符](#61-算术运算符)
- - [6.2. 关系运算符](#62-关系运算符)
- - [6.3. 布尔运算符](#63-布尔运算符)
- - [6.4. 逻辑运算符](#64-逻辑运算符)
- - [6.5. 字符串运算符](#65-字符串运算符)
- - [6.6. 文件测试运算符](#66-文件测试运算符)
-- [7. 控制语句](#7-控制语句)
- - [7.1. 条件语句](#71-条件语句)
- - [7.2. 循环语句](#72-循环语句)
-- [8. 函数](#8-函数)
- - [8.1. 位置参数](#81-位置参数)
- - [8.2. 函数处理参数](#82-函数处理参数)
-- [9. Shell 扩展](#9-shell-扩展)
-- [10. 流和重定向](#10-流和重定向)
- - [10.1. 输入、输出流](#101-输入输出流)
- - [10.2. 重定向](#102-重定向)
- - [10.3. `/dev/null` 文件](#103-devnull-文件)
-- [11. Debug](#11-debug)
-- [12. 更多内容](#12-更多内容)
-
-
-
-## 1. 简介
-
-### 1.1. 什么是 shell
-
-- Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。
-- Shell 既是一种命令语言,又是一种程序设计语言。
-- Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问 Linux 内核的服务。
-
-Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。
-
-### 1.2. 什么是 shell 脚本
-
-Shell 脚本(shell script),是一种为 shell 编写的脚本程序,一般文件后缀为 `.sh`。
-
-业界所说的 shell 通常都是指 shell 脚本,但 shell 和 shell script 是两个不同的概念。
-
-### 1.3. Shell 环境
-
-Shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
-
-Shell 的解释器种类众多,常见的有:
-
-- [sh](https://www.gnu.org/software/bash/) - 即 Bourne Shell。sh 是 Unix 标准默认的 shell。
-- [bash](https://www.gnu.org/software/bash/) - 即 Bourne Again Shell。bash 是 Linux 标准默认的 shell。
-- [fish](https://fishshell.com/) - 智能和用户友好的命令行 shell。
-- [xiki](http://xiki.org/) - 使 shell 控制台更友好,更强大。
-- [zsh](http://www.zsh.org/) - 功能强大的 shell 与脚本语言。
-
-#### 指定脚本解释器
-
-在 shell 脚本,`#!` 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器。`#!` 被称作[shebang(也称为 Hashbang )](https://zh.wikipedia.org/wiki/Shebang)。
-
-所以,你应该会在 shell 中,见到诸如以下的注释:
-
-- 指定 sh 解释器
-
-```bash
-#!/bin/sh
-```
-
-- 指定 bash 解释器
-
-```bash
-#!/bin/bash
-```
-
-> **注意**
->
-> 上面的指定解释器的方式是比较常见的,但有时候,你可能也会看到下面的方式:
->
-> ```bash
-> #!/usr/bin/env bash
-> ```
->
-> 这样做的好处是,系统会自动在 `PATH` 环境变量中查找你指定的程序(本例中的`bash`)。相比第一种写法,你应该尽量用这种写法,因为程序的路径是不确定的。这样写还有一个好处,操作系统的`PATH`变量有可能被配置为指向程序的另一个版本。比如,安装完新版本的`bash`,我们可能将其路径添加到`PATH`中,来“隐藏”老版本。如果直接用`#!/bin/bash`,那么系统会选择老版本的`bash`来执行脚本,如果用`#!/usr/bin/env bash`,则会使用新版本。
-
-### 1.4. 模式
-
-shell 有交互和非交互两种模式。
-
-#### 交互模式
-
-> 简单来说,你可以将 shell 的交互模式理解为执行命令行。
-
-看到形如下面的东西,说明 shell 处于交互模式下:
-
-```bash
-user@host:~$
-```
-
-接着,便可以输入一系列 Linux 命令,比如 `ls`,`grep`,`cd`,`mkdir`,`rm` 等等。
-
-#### 非交互模式
-
-> 简单来说,你可以将 shell 的非交互模式理解为执行 shell 脚本。
-
-在非交互模式下,shell 从文件或者管道中读取命令并执行。
-
-当 shell 解释器执行完文件中的最后一个命令,shell 进程终止,并回到父进程。
-
-可以使用下面的命令让 shell 以非交互模式运行:
-
-```bash
-sh /path/to/script.sh
-bash /path/to/script.sh
-source /path/to/script.sh
-./path/to/script.sh
-```
-
-上面的例子中,`script.sh`是一个包含 shell 解释器可以识别并执行的命令的普通文本文件,`sh`和`bash`是 shell 解释器程序。你可以使用任何喜欢的编辑器创建`script.sh`(vim,nano,Sublime Text, Atom 等等)。
-
-其中,`source /path/to/script.sh` 和 `./path/to/script.sh` 是等价的。
-
-除此之外,你还可以通过`chmod`命令给文件添加可执行的权限,来直接执行脚本文件:
-
-```bash
-chmod +x /path/to/script.sh #使脚本具有执行权限
-/path/to/test.sh
-```
-
-这种方式要求脚本文件的第一行必须指明运行该脚本的程序,比如:
-
-**:keyboard: 『示例源码』** [helloworld.sh](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos/helloworld.sh)
-
-```bash
-#!/usr/bin/env bash
-echo "Hello, world!"
-```
-
-上面的例子中,我们使用了一个很有用的命令`echo`来输出字符串到屏幕上。
-
-## 2. 基本语法
-
-### 2.1. 解释器
-
-前面虽然两次提到了`#!` ,但是本着重要的事情说三遍的精神,这里再强调一遍:
-
-在 shell 脚本,`#!` 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 解释器。`#!` 被称作[shebang(也称为 Hashbang )](https://zh.wikipedia.org/wiki/Shebang)。
-
-`#!` 决定了脚本可以像一个独立的可执行文件一样执行,而不用在终端之前输入`sh`, `bash`, `python`, `php`等。
-
-```bash
-# 以下两种方式都可以指定 shell 解释器为 bash,第二种方式更好
-#!/bin/bash
-#!/usr/bin/env bash
-```
-
-### 2.2. 注释
-
-注释可以说明你的代码是什么作用,以及为什么这样写。
-
-shell 语法中,注释是特殊的语句,会被 shell 解释器忽略。
-
-- 单行注释 - 以 `#` 开头,到行尾结束。
-- 多行注释 - 以 `:< test.txt
-```
-
-输出执行结果
-
-```bash
-echo `pwd`
-# Output:(当前目录路径)
-```
-
-**:keyboard: 『示例源码』** [echo-demo.sh](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos/echo-demo.sh)
-
-### 2.4. printf
-
-printf 用于格式化输出字符串。
-
-默认,printf 不会像 echo 一样自动添加换行符,如果需要换行可以手动添加 `\n`。
-
-**:keyboard: 『示例源码』** [printf-demo.sh](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos/printf-demo.sh)
-
-```bash
-# 单引号
-printf '%d %s\n' 1 "abc"
-# Output:1 abc
-
-# 双引号
-printf "%d %s\n" 1 "abc"
-# Output:1 abc
-
-# 无引号
-printf %s abcdef
-# Output: abcdef(并不会换行)
-
-# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出
-printf "%s\n" abc def
-# Output:
-# abc
-# def
-
-printf "%s %s %s\n" a b c d e f g h i j
-# Output:
-# a b c
-# d e f
-# g h i
-# j
-
-# 如果没有参数,那么 %s 用 NULL 代替,%d 用 0 代替
-printf "%s and %d \n"
-# Output:
-# and 0
-
-# 格式化输出
-printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
-printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
-printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
-printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
-# Output:
-# 姓名 性别 体重kg
-# 郭靖 男 66.12
-# 杨过 男 48.65
-# 郭芙 女 47.99
-```
-
-#### printf 的转义符
-
-| 序列 | 说明 |
-| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `\a` | 警告字符,通常为 ASCII 的 BEL 字符 |
-| `\b` | 后退 |
-| `\c` | 抑制(不显示)输出结果中任何结尾的换行字符(只在%b 格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略 |
-| `\f` | 换页(formfeed) |
-| `\n` | 换行 |
-| `\r` | 回车(Carriage return) |
-| `\t` | 水平制表符 |
-| `\v` | 垂直制表符 |
-| `\\` | 一个字面上的反斜杠字符 |
-| `\ddd` | 表示 1 到 3 位数八进制值的字符。仅在格式字符串中有效 |
-| `\0ddd` | 表示 1 到 3 位的八进制值字符 |
-
-## 3. 变量
-
-跟许多程序设计语言一样,你可以在 bash 中创建变量。
-
-Bash 中没有数据类型,bash 中的变量可以保存一个数字、一个字符、一个字符串等等。同时无需提前声明变量,给变量赋值会直接创建变量。
-
-### 3.1. 变量命名原则
-
-- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
-- 中间不能有空格,可以使用下划线(\_)。
-- 不能使用标点符号。
-- 不能使用 bash 里的关键字(可用 help 命令查看保留关键字)。
-
-### 3.2. 声明变量
-
-访问变量的语法形式为:`${var}` 和 `$var` 。
-
-变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,所以推荐加花括号。
-
-```bash
-word="hello"
-echo ${word}
-# Output: hello
-```
-
-### 3.3. 只读变量
-
-使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
-
-```bash
-rword="hello"
-echo ${rword}
-readonly rword
-# rword="bye" # 如果放开注释,执行时会报错
-```
-
-### 3.4. 删除变量
-
-使用 unset 命令可以删除变量。变量被删除后不能再次使用。unset 命令不能删除只读变量。
-
-```bash
-dword="hello" # 声明变量
-echo ${dword} # 输出变量值
-# Output: hello
-
-unset dword # 删除变量
-echo ${dword}
-# Output: (空)
-```
-
-### 3.5. 变量类型
-
-- **局部变量** - 局部变量是仅在某个脚本内部有效的变量。它们不能被其他的程序和脚本访问。
-- **环境变量** - 环境变量是对当前 shell 会话内所有的程序或脚本都可见的变量。创建它们跟创建局部变量类似,但使用的是 `export` 关键字,shell 脚本也可以定义环境变量。
-
-常见的环境变量:
-
-| 变量 | 描述 |
-| --------- | -------------------------------------------------- |
-| `$HOME` | 当前用户的用户目录 |
-| `$PATH` | 用分号分隔的目录列表,shell 会到这些目录中查找命令 |
-| `$PWD` | 当前工作目录 |
-| `$RANDOM` | 0 到 32767 之间的整数 |
-| `$UID` | 数值类型,当前用户的用户 ID |
-| `$PS1` | 主要系统输入提示符 |
-| `$PS2` | 次要系统输入提示符 |
-
-[这里](http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html###sect_03_02_04) 有一张更全面的 Bash 环境变量列表。
-
-### 3.6. 变量示例源码
-
-**⌨️ 『示例源码』** [variable-demo.sh](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos/variable-demo.sh)
-
-## 4. 字符串
-
-### 4.1. 单引号和双引号
-
-shell 字符串可以用单引号 `''`,也可以用双引号 `“”`,也可以不用引号。
-
-- 单引号的特点
- - 单引号里不识别变量
- - 单引号里不能出现单独的单引号(使用转义符也不行),但可成对出现,作为字符串拼接使用。
-- 双引号的特点
- - 双引号里识别变量
- - 双引号里可以出现转义字符
-
-综上,推荐使用双引号。
-
-### 4.2. 拼接字符串
-
-```bash
-# 使用单引号拼接
-name1='white'
-str1='hello, '${name1}''
-str2='hello, ${name1}'
-echo ${str1}_${str2}
-# Output:
-# hello, white_hello, ${name1}
-
-# 使用双引号拼接
-name2="black"
-str3="hello, "${name2}""
-str4="hello, ${name2}"
-echo ${str3}_${str4}
-# Output:
-# hello, black_hello, black
-```
-
-### 4.3. 获取字符串长度
-
-```bash
-text="12345"
-echo ${#text}
-# Output:
-# 5
-```
-
-### 4.4. 截取子字符串
-
-```bash
-text="12345"
-echo ${text:2:2}
-# Output:
-# 34
-```
-
-从第 3 个字符开始,截取 2 个字符
-
-### 4.5. 查找子字符串
-
-```bash
-#!/usr/bin/env bash
-
-text="hello"
-echo `expr index "${text}" ll`
-
-# Execute: ./str-demo5.sh
-# Output:
-# 3
-```
-
-查找 `ll` 子字符在 `hello` 字符串中的起始位置。
-
-### 4.6. 字符串示例源码
-
-**⌨️ 『示例源码』** [string-demo.sh](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos/string-demo.sh)
-
-## 5. 数组
-
-bash 只支持一维数组。
-
-数组下标从 0 开始,下标可以是整数或算术表达式,其值应大于或等于 0。
-
-### 5.1. 创建数组
-
-```bash
-# 创建数组的不同方式
-nums=([2]=2 [0]=0 [1]=1)
-colors=(red yellow "dark blue")
-```
-
-### 5.2. 访问数组元素
-
-- **访问数组的单个元素:**
-
-```bash
-echo ${nums[1]}
-# Output: 1
-```
-
-- **访问数组的所有元素:**
-
-```bash
-echo ${colors[*]}
-# Output: red yellow dark blue
-
-echo ${colors[@]}
-# Output: red yellow dark blue
-```
-
-上面两行有很重要(也很微妙)的区别:
-
-为了将数组中每个元素单独一行输出,我们用 `printf` 命令:
-
-```bash
-printf "+ %s\n" ${colors[*]}
-# Output:
-# + red
-# + yellow
-# + dark
-# + blue
-```
-
-为什么`dark`和`blue`各占了一行?尝试用引号包起来:
-
-```bash
-printf "+ %s\n" "${colors[*]}"
-# Output:
-# + red yellow dark blue
-```
-
-现在所有的元素都在一行输出 —— 这不是我们想要的!让我们试试`${colors[@]}`
-
-```bash
-printf "+ %s\n" "${colors[@]}"
-# Output:
-# + red
-# + yellow
-# + dark blue
-```
-
-在引号内,`${colors[@]}`将数组中的每个元素扩展为一个单独的参数;数组元素中的空格得以保留。
-
-- **访问数组的部分元素:**
-
-```bash
-echo ${nums[@]:0:2}
-# Output:
-# 0 1
-```
-
-在上面的例子中,`${array[@]}` 扩展为整个数组,`:0:2`取出了数组中从 0 开始,长度为 2 的元素。
-
-### 5.3. 访问数组长度
-
-```bash
-echo ${#nums[*]}
-# Output:
-# 3
-```
-
-### 5.4. 向数组中添加元素
-
-向数组中添加元素也非常简单:
-
-```bash
-colors=(white "${colors[@]}" green black)
-echo ${colors[@]}
-# Output:
-# white red yellow dark blue green black
-```
-
-上面的例子中,`${colors[@]}` 扩展为整个数组,并被置换到复合赋值语句中,接着,对数组`colors`的赋值覆盖了它原来的值。
-
-### 5.5. 从数组中删除元素
-
-用`unset`命令来从数组中删除一个元素:
-
-```bash
-unset nums[0]
-echo ${nums[@]}
-# Output:
-# 1 2
-```
-
-### 5.6. 数组示例源码
-
-**:keyboard: 『示例源码』** [array-demo.sh](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos/array-demo.sh)
-
-## 6. 运算符
-
-### 6.1. 算术运算符
-
-下表列出了常用的算术运算符,假定变量 x 为 10,变量 y 为 20:
-
-| 运算符 | 说明 | 举例 |
-| ------ | --------------------------------------------- | ------------------------------ |
-| + | 加法 | `expr $x + $y` 结果为 30。 |
-| - | 减法 | `expr $x - $y` 结果为 -10。 |
-| \* | 乘法 | `expr $x * $y` 结果为 200。 |
-| / | 除法 | `expr $y / $x` 结果为 2。 |
-| % | 取余 | `expr $y % $x` 结果为 0。 |
-| = | 赋值 | `x=$y` 将把变量 y 的值赋给 x。 |
-| == | 相等。用于比较两个数字,相同则返回 true。 | `[ $x == $y ]` 返回 false。 |
-| != | 不相等。用于比较两个数字,不相同则返回 true。 | `[ $x != $y ]` 返回 true。 |
-
-**注意:**条件表达式要放在方括号之间,并且要有空格,例如: `[$x==$y]` 是错误的,必须写成 `[ $x == $y ]`。
-
-**:keyboard: 『示例源码』** [operator-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/operator/operator-demo.sh)
-
-```bash
-x=10
-y=20
-
-echo "x=${x}, y=${y}"
-
-val=`expr ${x} + ${y}`
-echo "${x} + ${y} = $val"
-
-val=`expr ${x} - ${y}`
-echo "${x} - ${y} = $val"
-
-val=`expr ${x} \* ${y}`
-echo "${x} * ${y} = $val"
-
-val=`expr ${y} / ${x}`
-echo "${y} / ${x} = $val"
-
-val=`expr ${y} % ${x}`
-echo "${y} % ${x} = $val"
-
-if [[ ${x} == ${y} ]]
-then
- echo "${x} = ${y}"
-fi
-if [[ ${x} != ${y} ]]
-then
- echo "${x} != ${y}"
-fi
-
-# Execute: ./operator-demo.sh
-# Output:
-# x=10, y=20
-# 10 + 20 = 30
-# 10 - 20 = -10
-# 10 * 20 = 200
-# 20 / 10 = 2
-# 20 % 10 = 0
-# 10 != 20
-```
-
-### 6.2. 关系运算符
-
-关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
-
-下表列出了常用的关系运算符,假定变量 x 为 10,变量 y 为 20:
-
-| 运算符 | 说明 | 举例 |
-| ------ | ----------------------------------------------------- | ---------------------------- |
-| `-eq` | 检测两个数是否相等,相等返回 true。 | `[ $a -eq $b ]`返回 false。 |
-| `-ne` | 检测两个数是否相等,不相等返回 true。 | `[ $a -ne $b ]` 返回 true。 |
-| `-gt` | 检测左边的数是否大于右边的,如果是,则返回 true。 | `[ $a -gt $b ]` 返回 false。 |
-| `-lt` | 检测左边的数是否小于右边的,如果是,则返回 true。 | `[ $a -lt $b ]` 返回 true。 |
-| `-ge` | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | `[ $a -ge $b ]` 返回 false。 |
-| `-le` | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | `[ $a -le $b ]`返回 true。 |
-
-**:keyboard: 『示例源码』** [operator-demo2.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/operator/operator-demo2.sh)
-
-```bash
-x=10
-y=20
-
-echo "x=${x}, y=${y}"
-
-if [[ ${x} -eq ${y} ]]; then
- echo "${x} -eq ${y} : x 等于 y"
-else
- echo "${x} -eq ${y}: x 不等于 y"
-fi
-
-if [[ ${x} -ne ${y} ]]; then
- echo "${x} -ne ${y}: x 不等于 y"
-else
- echo "${x} -ne ${y}: x 等于 y"
-fi
-
-if [[ ${x} -gt ${y} ]]; then
- echo "${x} -gt ${y}: x 大于 y"
-else
- echo "${x} -gt ${y}: x 不大于 y"
-fi
-
-if [[ ${x} -lt ${y} ]]; then
- echo "${x} -lt ${y}: x 小于 y"
-else
- echo "${x} -lt ${y}: x 不小于 y"
-fi
-
-if [[ ${x} -ge ${y} ]]; then
- echo "${x} -ge ${y}: x 大于或等于 y"
-else
- echo "${x} -ge ${y}: x 小于 y"
-fi
-
-if [[ ${x} -le ${y} ]]; then
- echo "${x} -le ${y}: x 小于或等于 y"
-else
- echo "${x} -le ${y}: x 大于 y"
-fi
-
-# Execute: ./operator-demo2.sh
-# Output:
-# x=10, y=20
-# 10 -eq 20: x 不等于 y
-# 10 -ne 20: x 不等于 y
-# 10 -gt 20: x 不大于 y
-# 10 -lt 20: x 小于 y
-# 10 -ge 20: x 小于 y
-# 10 -le 20: x 小于或等于 y
-```
-
-### 6.3. 布尔运算符
-
-下表列出了常用的布尔运算符,假定变量 x 为 10,变量 y 为 20:
-
-| 运算符 | 说明 | 举例 |
-| ------ | --------------------------------------------------- | ------------------------------------------ |
-| `!` | 非运算,表达式为 true 则返回 false,否则返回 true。 | `[ ! false ]` 返回 true。 |
-| `-o` | 或运算,有一个表达式为 true 则返回 true。 | `[ $a -lt 20 -o $b -gt 100 ]` 返回 true。 |
-| `-a` | 与运算,两个表达式都为 true 才返回 true。 | `[ $a -lt 20 -a $b -gt 100 ]` 返回 false。 |
-
-**:keyboard: 『示例源码』** [operator-demo3.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/operator/operator-demo3.sh)
-
-```bash
-x=10
-y=20
-
-echo "x=${x}, y=${y}"
-
-if [[ ${x} != ${y} ]]; then
- echo "${x} != ${y} : x 不等于 y"
-else
- echo "${x} != ${y}: x 等于 y"
-fi
-
-if [[ ${x} -lt 100 && ${y} -gt 15 ]]; then
- echo "${x} 小于 100 且 ${y} 大于 15 : 返回 true"
-else
- echo "${x} 小于 100 且 ${y} 大于 15 : 返回 false"
-fi
-
-if [[ ${x} -lt 100 || ${y} -gt 100 ]]; then
- echo "${x} 小于 100 或 ${y} 大于 100 : 返回 true"
-else
- echo "${x} 小于 100 或 ${y} 大于 100 : 返回 false"
-fi
-
-if [[ ${x} -lt 5 || ${y} -gt 100 ]]; then
- echo "${x} 小于 5 或 ${y} 大于 100 : 返回 true"
-else
- echo "${x} 小于 5 或 ${y} 大于 100 : 返回 false"
-fi
-
-# Execute: ./operator-demo3.sh
-# Output:
-# x=10, y=20
-# 10 != 20 : x 不等于 y
-# 10 小于 100 且 20 大于 15 : 返回 true
-# 10 小于 100 或 20 大于 100 : 返回 true
-# 10 小于 5 或 20 大于 100 : 返回 false
-```
-
-### 6.4. 逻辑运算符
-
-以下介绍 Shell 的逻辑运算符,假定变量 x 为 10,变量 y 为 20:
-
-| 运算符 | 说明 | 举例 |
-| ------ | ---------- | ----------------------------------------------- |
-| `&&` | 逻辑的 AND | `[[ ${x} -lt 100 && ${y} -gt 100 ]]` 返回 false |
-| `||` | 逻辑的 OR | `[[ ${x} -lt 100 || ${y} -gt 100 ]]` 返回 true |
-
-**:keyboard: 『示例源码』** [operator-demo4.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/operator/operator-demo4.sh)
-
-```bash
-x=10
-y=20
-
-echo "x=${x}, y=${y}"
-
-if [[ ${x} -lt 100 && ${y} -gt 100 ]]
-then
- echo "${x} -lt 100 && ${y} -gt 100 返回 true"
-else
- echo "${x} -lt 100 && ${y} -gt 100 返回 false"
-fi
-
-if [[ ${x} -lt 100 || ${y} -gt 100 ]]
-then
- echo "${x} -lt 100 || ${y} -gt 100 返回 true"
-else
- echo "${x} -lt 100 || ${y} -gt 100 返回 false"
-fi
-
-# Execute: ./operator-demo4.sh
-# Output:
-# x=10, y=20
-# 10 -lt 100 && 20 -gt 100 返回 false
-# 10 -lt 100 || 20 -gt 100 返回 true
-```
-
-### 6.5. 字符串运算符
-
-下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg":
-
-| 运算符 | 说明 | 举例 |
-| ------ | ------------------------------------------ | -------------------------- |
-| `=` | 检测两个字符串是否相等,相等返回 true。 | `[ $a = $b ]` 返回 false。 |
-| `!=` | 检测两个字符串是否相等,不相等返回 true。 | `[ $a != $b ]` 返回 true。 |
-| `-z` | 检测字符串长度是否为 0,为 0 返回 true。 | `[ -z $a ]` 返回 false。 |
-| `-n` | 检测字符串长度是否为 0,不为 0 返回 true。 | `[ -n $a ]` 返回 true。 |
-| `str` | 检测字符串是否为空,不为空返回 true。 | `[ $a ]` 返回 true。 |
-
-**:keyboard: 『示例源码』** [operator-demo5.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/operator/operator-demo5.sh)
-
-```bash
-x="abc"
-y="xyz"
-
-
-echo "x=${x}, y=${y}"
-
-if [[ ${x} = ${y} ]]; then
- echo "${x} = ${y} : x 等于 y"
-else
- echo "${x} = ${y}: x 不等于 y"
-fi
-
-if [[ ${x} != ${y} ]]; then
- echo "${x} != ${y} : x 不等于 y"
-else
- echo "${x} != ${y}: x 等于 y"
-fi
-
-if [[ -z ${x} ]]; then
- echo "-z ${x} : 字符串长度为 0"
-else
- echo "-z ${x} : 字符串长度不为 0"
-fi
-
-if [[ -n "${x}" ]]; then
- echo "-n ${x} : 字符串长度不为 0"
-else
- echo "-n ${x} : 字符串长度为 0"
-fi
-
-if [[ ${x} ]]; then
- echo "${x} : 字符串不为空"
-else
- echo "${x} : 字符串为空"
-fi
-
-# Execute: ./operator-demo5.sh
-# Output:
-# x=abc, y=xyz
-# abc = xyz: x 不等于 y
-# abc != xyz : x 不等于 y
-# -z abc : 字符串长度不为 0
-# -n abc : 字符串长度不为 0
-# abc : 字符串不为空
-```
-
-### 6.6. 文件测试运算符
-
-文件测试运算符用于检测 Unix 文件的各种属性。
-
-属性检测描述如下:
-
-| 操作符 | 说明 | 举例 |
-| ------- | --------------------------------------------------------------------------- | --------------------------- |
-| -b file | 检测文件是否是块设备文件,如果是,则返回 true。 | `[ -b $file ]` 返回 false。 |
-| -c file | 检测文件是否是字符设备文件,如果是,则返回 true。 | `[ -c $file ]` 返回 false。 |
-| -d file | 检测文件是否是目录,如果是,则返回 true。 | `[ -d $file ]` 返回 false。 |
-| -f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | `[ -f $file ]` 返回 true。 |
-| -g file | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | `[ -g $file ]` 返回 false。 |
-| -k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | `[ -k $file ]`返回 false。 |
-| -p file | 检测文件是否是有名管道,如果是,则返回 true。 | `[ -p $file ]` 返回 false。 |
-| -u file | 检测文件是否设置了 SUID 位,如果是,则返回 true。 | `[ -u $file ]` 返回 false。 |
-| -r file | 检测文件是否可读,如果是,则返回 true。 | `[ -r $file ]` 返回 true。 |
-| -w file | 检测文件是否可写,如果是,则返回 true。 | `[ -w $file ]` 返回 true。 |
-| -x file | 检测文件是否可执行,如果是,则返回 true。 | `[ -x $file ]` 返回 true。 |
-| -s file | 检测文件是否为空(文件大小是否大于 0),不为空返回 true。 | `[ -s $file ]` 返回 true。 |
-| -e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | `[ -e $file ]` 返回 true。 |
-
-**:keyboard: 『示例源码』** [operator-demo6.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/operator/operator-demo6.sh)
-
-```bash
-file="/etc/hosts"
-
-if [[ -r ${file} ]]; then
- echo "${file} 文件可读"
-else
- echo "${file} 文件不可读"
-fi
-if [[ -w ${file} ]]; then
- echo "${file} 文件可写"
-else
- echo "${file} 文件不可写"
-fi
-if [[ -x ${file} ]]; then
- echo "${file} 文件可执行"
-else
- echo "${file} 文件不可执行"
-fi
-if [[ -f ${file} ]]; then
- echo "${file} 文件为普通文件"
-else
- echo "${file} 文件为特殊文件"
-fi
-if [[ -d ${file} ]]; then
- echo "${file} 文件是个目录"
-else
- echo "${file} 文件不是个目录"
-fi
-if [[ -s ${file} ]]; then
- echo "${file} 文件不为空"
-else
- echo "${file} 文件为空"
-fi
-if [[ -e ${file} ]]; then
- echo "${file} 文件存在"
-else
- echo "${file} 文件不存在"
-fi
-
-# Execute: ./operator-demo6.sh
-# Output:(根据文件的实际情况,输出结果可能不同)
-# /etc/hosts 文件可读
-# /etc/hosts 文件可写
-# /etc/hosts 文件不可执行
-# /etc/hosts 文件为普通文件
-# /etc/hosts 文件不是个目录
-# /etc/hosts 文件不为空
-# /etc/hosts 文件存在
-```
-
-## 7. 控制语句
-
-### 7.1. 条件语句
-
-跟其它程序设计语言一样,Bash 中的条件语句让我们可以决定一个操作是否被执行。结果取决于一个包在`[[ ]]`里的表达式。
-
-由`[[ ]]`(`sh`中是`[ ]`)包起来的表达式被称作 **检测命令** 或 **基元**。这些表达式帮助我们检测一个条件的结果。这里可以找到有关[bash 中单双中括号区别](http://serverfault.com/a/52050)的答案。
-
-共有两个不同的条件表达式:`if`和`case`。
-
-#### `if`
-
-(1)`if` 语句
-
-`if`在使用上跟其它语言相同。如果中括号里的表达式为真,那么`then`和`fi`之间的代码会被执行。`fi`标志着条件代码块的结束。
-
-```bash
-# 写成一行
-if [[ 1 -eq 1 ]]; then echo "1 -eq 1 result is: true"; fi
-# Output: 1 -eq 1 result is: true
-
-# 写成多行
-if [[ "abc" -eq "abc" ]]
-then
- echo ""abc" -eq "abc" result is: true"
-fi
-# Output: abc -eq abc result is: true
-```
-
-(2)`if else` 语句
-
-同样,我们可以使用`if..else`语句,例如:
-
-```bash
-if [[ 2 -ne 1 ]]; then
- echo "true"
-else
- echo "false"
-fi
-# Output: true
-```
-
-(3)`if elif else` 语句
-
-有些时候,`if..else`不能满足我们的要求。别忘了`if..elif..else`,使用起来也很方便。
-
-```bash
-x=10
-y=20
-if [[ ${x} > ${y} ]]; then
- echo "${x} > ${y}"
-elif [[ ${x} < ${y} ]]; then
- echo "${x} < ${y}"
-else
- echo "${x} = ${y}"
-fi
-# Output: 10 < 20
-```
-
-**:keyboard: 『示例源码』** [if-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/statement/if-demo.sh)
-
-#### `case`
-
-如果你需要面对很多情况,分别要采取不同的措施,那么使用`case`会比嵌套的`if`更有用。使用`case`来解决复杂的条件判断,看起来像下面这样:
-
-**:keyboard: 『示例源码』** [case-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/statement/case-demo.sh)
-
-```bash
-exec
-case ${oper} in
- "+")
- val=`expr ${x} + ${y}`
- echo "${x} + ${y} = ${val}"
- ;;
- "-")
- val=`expr ${x} - ${y}`
- echo "${x} - ${y} = ${val}"
- ;;
- "*")
- val=`expr ${x} \* ${y}`
- echo "${x} * ${y} = ${val}"
- ;;
- "/")
- val=`expr ${x} / ${y}`
- echo "${x} / ${y} = ${val}"
- ;;
- *)
- echo "Unknown oper!"
- ;;
-esac
-```
-
-每种情况都是匹配了某个模式的表达式。`|`用来分割多个模式,`)`用来结束一个模式序列。第一个匹配上的模式对应的命令将会被执行。`*`代表任何不匹配以上给定模式的模式。命令块儿之间要用`;;`分隔。
-
-### 7.2. 循环语句
-
-循环其实不足为奇。跟其它程序设计语言一样,bash 中的循环也是只要控制条件为真就一直迭代执行的代码块。
-
-Bash 中有四种循环:`for`,`while`,`until`和`select`。
-
-#### `for`循环
-
-`for`与它在 C 语言中的姊妹非常像。看起来是这样:
-
-```bash
-for arg in elem1 elem2 ... elemN
-do
- ### 语句
-done
-```
-
-在每次循环的过程中,`arg`依次被赋值为从`elem1`到`elemN`。这些值还可以是通配符或者[大括号扩展](https://github.com/denysdovhan/bash-handbook/blob/master/translations/zh-CN/README.md#%E5%A4%A7%E6%8B%AC%E5%8F%B7%E6%89%A9%E5%B1%95)。
-
-当然,我们还可以把`for`循环写在一行,但这要求`do`之前要有一个分号,就像下面这样:
-
-```bash
-for i in {1..5}; do echo $i; done
-```
-
-还有,如果你觉得`for..in..do`对你来说有点奇怪,那么你也可以像 C 语言那样使用`for`,比如:
-
-```bash
-for (( i = 0; i < 10; i++ )); do
- echo $i
-done
-```
-
-当我们想对一个目录下的所有文件做同样的操作时,`for`就很方便了。举个例子,如果我们想把所有的`.bash`文件移动到`script`文件夹中,并给它们可执行权限,我们的脚本可以这样写:
-
-```bash
-DIR=/home/zp
-for FILE in ${DIR}/*.sh; do
- mv "$FILE" "${DIR}/scripts"
-done
-# 将 /home/zp 目录下所有 sh 文件拷贝到 /home/zp/scripts
-```
-
-**:keyboard: 『示例源码』** [for-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/statement/for-demo.sh)
-
-#### `while`循环
-
-`while`循环检测一个条件,只要这个条件为 _真_,就执行一段命令。被检测的条件跟`if..then`中使用的[基元](https://github.com/denysdovhan/bash-handbook/blob/master/translations/zh-CN/README.md#%E5%9F%BA%E5%85%83%E5%92%8C%E7%BB%84%E5%90%88%E8%A1%A8%E8%BE%BE%E5%BC%8F)并无二异。因此一个`while`循环看起来会是这样:
-
-```bash
-while [[ condition ]]
-do
- ### 语句
-done
-```
-
-跟`for`循环一样,如果我们把`do`和被检测的条件写到一行,那么必须要在`do`之前加一个分号。
-
-比如下面这个例子:
-
-```bash
-### 0到9之间每个数的平方
-x=0
-while [[ ${x} -lt 10 ]]; do
- echo $((x * x))
- x=$((x + 1))
-done
-# Output:
-# 0
-# 1
-# 4
-# 9
-# 16
-# 25
-# 36
-# 49
-# 64
-# 81
-```
-
-**:keyboard: 『示例源码』** [while-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/statement/while-demo.sh)
-
-#### `until`循环
-
-`until`循环跟`while`循环正好相反。它跟`while`一样也需要检测一个测试条件,但不同的是,只要该条件为 _假_ 就一直执行循环:
-
-```bash
-x=0
-until [[ ${x} -ge 5 ]]; do
- echo ${x}
- x=`expr ${x} + 1`
-done
-# Output:
-# 0
-# 1
-# 2
-# 3
-# 4
-```
-
-**:keyboard: 『示例源码』** [until-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/statement/until-demo.sh)
-
-#### `select`循环
-
-`select`循环帮助我们组织一个用户菜单。它的语法几乎跟`for`循环一致:
-
-```bash
-select answer in elem1 elem2 ... elemN
-do
- ### 语句
-done
-```
-
-`select`会打印`elem1..elemN`以及它们的序列号到屏幕上,之后会提示用户输入。通常看到的是`$?`(`PS3`变量)。用户的选择结果会被保存到`answer`中。如果`answer`是一个在`1..N`之间的数字,那么`语句`会被执行,紧接着会进行下一次迭代 —— 如果不想这样的话我们可以使用`break`语句。
-
-一个可能的实例可能会是这样:
-
-```bash
-#!/usr/bin/env bash
-
-PS3="Choose the package manager: "
-select ITEM in bower npm gem pip
-do
-echo -n "Enter the package name: " && read PACKAGE
-case ${ITEM} in
- bower) bower install ${PACKAGE} ;;
- npm) npm install ${PACKAGE} ;;
- gem) gem install ${PACKAGE} ;;
- pip) pip install ${PACKAGE} ;;
-esac
-break # 避免无限循环
-done
-```
-
-这个例子,先询问用户他想使用什么包管理器。接着,又询问了想安装什么包,最后执行安装操作。
-
-运行这个脚本,会得到如下输出:
-
-```bash
-$ ./my_script
-1) bower
-2) npm
-3) gem
-4) pip
-Choose the package manager: 2
-Enter the package name: gitbook-cli
-```
-
-**:keyboard: 『示例源码』** [select-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/statement/select-demo.sh)
-
-#### `break` 和 `continue`
-
-如果想提前结束一个循环或跳过某次循环执行,可以使用 shell 的`break`和`continue`语句来实现。它们可以在任何循环中使用。
-
-> `break`语句用来提前结束当前循环。
->
-> `continue`语句用来跳过某次迭代。
-
-**:keyboard: 『示例源码』** [break-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/statement/break-demo.sh)
-
-```bash
-# 查找 10 以内第一个能整除 2 和 3 的正整数
-i=1
-while [[ ${i} -lt 10 ]]; do
- if [[ $((i % 3)) -eq 0 ]] && [[ $((i % 2)) -eq 0 ]]; then
- echo ${i}
- break;
- fi
- i=`expr ${i} + 1`
-done
-# Output: 6
-```
-
-**:keyboard: 『示例源码』** [continue-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/statement/continue-demo.sh)
-
-```bash
-# 打印10以内的奇数
-for (( i = 0; i < 10; i ++ )); do
- if [[ $((i % 2)) -eq 0 ]]; then
- continue;
- fi
- echo ${i}
-done
-# Output:
-# 1
-# 3
-# 5
-# 7
-# 9
-```
-
-## 8. 函数
-
-bash 函数定义语法如下:
-
-```bash
-[ function ] funname [()] {
- action;
- [return int;]
-}
-```
-
-> :bulb: 说明:
->
-> 1. 函数定义时,`function` 关键字可有可无。
-> 2. 函数返回值 - return 返回函数返回值,返回值类型只能为整数(0-255)。如果不加 return 语句,shell 默认将以最后一条命令的运行结果,作为函数返回值。
-> 3. 函数返回值在调用该函数后通过 `$?` 来获得。
-> 4. 所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至 shell 解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。
-
-**:keyboard: 『示例源码』** [function-demo.sh](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos//function/function-demo.sh)
-
-```bash
-#!/usr/bin/env bash
-
-calc(){
- PS3="choose the oper: "
- select oper in + - \* / # 生成操作符选择菜单
- do
- echo -n "enter first num: " && read x # 读取输入参数
- echo -n "enter second num: " && read y # 读取输入参数
- exec
- case ${oper} in
- "+")
- return $((${x} + ${y}))
- ;;
- "-")
- return $((${x} - ${y}))
- ;;
- "*")
- return $((${x} * ${y}))
- ;;
- "/")
- return $((${x} / ${y}))
- ;;
- *)
- echo "${oper} is not support!"
- return 0
- ;;
- esac
- break
- done
-}
-calc
-echo "the result is: $?" # $? 获取 calc 函数返回值
-```
-
-执行结果:
-
-```bash
-$ ./function-demo.sh
-1) +
-2) -
-3) *
-4) /
-choose the oper: 3
-enter first num: 10
-enter second num: 10
-the result is: 100
-```
-
-### 8.1. 位置参数
-
-**位置参数**是在调用一个函数并传给它参数时创建的变量。
-
-位置参数变量表:
-
-| 变量 | 描述 |
-| -------------- | ------------------------------ |
-| `$0` | 脚本名称 |
-| `$1 … $9` | 第 1 个到第 9 个参数列表 |
-| `${10} … ${N}` | 第 10 个到 N 个参数列表 |
-| `$*` or `$@` | 除了`$0`外的所有位置参数 |
-| `$#` | 不包括`$0`在内的位置参数的个数 |
-| `$FUNCNAME` | 函数名称(仅在函数内部有值) |
-
-**:keyboard: 『示例源码』** [function-demo2.sh](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos//function/function-demo2.sh)
-
-```bash
-#!/usr/bin/env bash
-
-x=0
-if [[ -n $1 ]]; then
- echo "第一个参数为:$1"
- x=$1
-else
- echo "第一个参数为空"
-fi
-
-y=0
-if [[ -n $2 ]]; then
- echo "第二个参数为:$2"
- y=$2
-else
- echo "第二个参数为空"
-fi
-
-paramsFunction(){
- echo "函数第一个入参:$1"
- echo "函数第二个入参:$2"
-}
-paramsFunction ${x} ${y}
-```
-
-执行结果:
-
-```bash
-$ ./function-demo2.sh
-第一个参数为空
-第二个参数为空
-函数第一个入参:0
-函数第二个入参:0
-
-$ ./function-demo2.sh 10 20
-第一个参数为:10
-第二个参数为:20
-函数第一个入参:10
-函数第二个入参:20
-```
-
-执行 `./variable-demo4.sh hello world` ,然后在脚本中通过 `$1`、`$2` ... 读取第 1 个参数、第 2 个参数。。。
-
-### 8.2. 函数处理参数
-
-另外,还有几个特殊字符用来处理参数:
-
-| 参数处理 | 说明 |
-| -------- | ------------------------------------------------ |
-| `$#` | 返回参数个数 |
-| `$*` | 返回所有参数 |
-| `$$` | 脚本运行的当前进程 ID 号 |
-| `$!` | 后台运行的最后一个进程的 ID 号 |
-| `$@` | 返回所有参数 |
-| `$-` | 返回 Shell 使用的当前选项,与 set 命令功能相同。 |
-| `$?` | 函数返回值 |
-
-**:keyboard: 『示例源码』** [function-demo3.sh](https://github.com/dunwu/linux-tutorial/tree/master/codes/shell/demos//function/function-demo3.sh)
-
-```bash
-runner() {
- return 0
-}
-
-name=zp
-paramsFunction(){
- echo "函数第一个入参:$1"
- echo "函数第二个入参:$2"
- echo "传递到脚本的参数个数:$#"
- echo "所有参数:"
- printf "+ %s\n" "$*"
- echo "脚本运行的当前进程 ID 号:$$"
- echo "后台运行的最后一个进程的 ID 号:$!"
- echo "所有参数:"
- printf "+ %s\n" "$@"
- echo "Shell 使用的当前选项:$-"
- runner
- echo "runner 函数的返回值:$?"
-}
-paramsFunction 1 "abc" "hello, \"zp\""
-# Output:
-# 函数第一个入参:1
-# 函数第二个入参:abc
-# 传递到脚本的参数个数:3
-# 所有参数:
-# + 1 abc hello, "zp"
-# 脚本运行的当前进程 ID 号:26400
-# 后台运行的最后一个进程的 ID 号:
-# 所有参数:
-# + 1
-# + abc
-# + hello, "zp"
-# Shell 使用的当前选项:hB
-# runner 函数的返回值:0
-```
-
-## 9. Shell 扩展
-
-_扩展_ 发生在一行命令被分成一个个的 _记号(tokens)_ 之后。换言之,扩展是一种执行数学运算的机制,还可以用来保存命令的执行结果,等等。
-
-感兴趣的话可以阅读[关于 shell 扩展的更多细节](https://www.gnu.org/software/bash/manual/bash.html###Shell-Expansions)。
-
-#### 大括号扩展
-
-大括号扩展让生成任意的字符串成为可能。它跟 _文件名扩展_ 很类似,举个例子:
-
-```bash
-echo beg{i,a,u}n ### begin began begun
-```
-
-大括号扩展还可以用来创建一个可被循环迭代的区间。
-
-```bash
-echo {0..5} ### 0 1 2 3 4 5
-echo {00..8..2} ### 00 02 04 06 08
-```
-
-#### 命令置换
-
-命令置换允许我们对一个命令求值,并将其值置换到另一个命令或者变量赋值表达式中。当一个命令被``或`$()`包围时,命令置换将会执行。举个例子:
-
-```bash
-now=`date +%T`
-### or
-now=$(date +%T)
-
-echo $now ### 19:08:26
-```
-
-#### 算数扩展
-
-在 bash 中,执行算数运算是非常方便的。算数表达式必须包在`$(( ))`中。算数扩展的格式为:
-
-```bash
-result=$(( ((10 + 5*3) - 7) / 2 ))
-echo $result ### 9
-```
-
-在算数表达式中,使用变量无需带上`$`前缀:
-
-```bash
-x=4
-y=7
-echo $(( x + y )) ### 11
-echo $(( ++x + y++ )) ### 12
-echo $(( x + y )) ### 13
-```
-
-#### 单引号和双引号
-
-单引号和双引号之间有很重要的区别。在双引号中,变量引用或者命令置换是会被展开的。在单引号中是不会的。举个例子:
-
-```bash
-echo "Your home: $HOME" ### Your home: /Users/
-echo 'Your home: $HOME' ### Your home: $HOME
-```
-
-当局部变量和环境变量包含空格时,它们在引号中的扩展要格外注意。随便举个例子,假如我们用`echo`来输出用户的输入:
-
-```bash
-INPUT="A string with strange whitespace."
-echo $INPUT ### A string with strange whitespace.
-echo "$INPUT" ### A string with strange whitespace.
-```
-
-调用第一个`echo`时给了它 5 个单独的参数 —— `$INPUT` 被分成了单独的词,`echo`在每个词之间打印了一个空格。第二种情况,调用`echo`时只给了它一个参数(整个\$INPUT 的值,包括其中的空格)。
-
-来看一个更严肃的例子:
-
-```bash
-FILE="Favorite Things.txt"
-cat $FILE ### 尝试输出两个文件: `Favorite` 和 `Things.txt`
-cat "$FILE" ### 输出一个文件: `Favorite Things.txt`
-```
-
-尽管这个问题可以通过把 FILE 重命名成`Favorite-Things.txt`来解决,但是,假如这个值来自某个环境变量,来自一个位置参数,或者来自其它命令(`find`, `cat`, 等等)呢。因此,如果输入 _可能_ 包含空格,务必要用引号把表达式包起来。
-
-## 10. 流和重定向
-
-Bash 有很强大的工具来处理程序之间的协同工作。使用流,我们能将一个程序的输出发送到另一个程序或文件,因此,我们能方便地记录日志或做一些其它我们想做的事。
-
-管道给了我们创建传送带的机会,控制程序的执行成为可能。
-
-学习如何使用这些强大的、高级的工具是非常非常重要的。
-
-### 10.1. 输入、输出流
-
-Bash 接收输入,并以字符序列或 **字符流** 的形式产生输出。这些流能被重定向到文件或另一个流中。
-
-有三个文件描述符:
-
-| 代码 | 描述符 | 描述 |
-| ---- | -------- | ------------ |
-| `0` | `stdin` | 标准输入 |
-| `1` | `stdout` | 标准输出 |
-| `2` | `stderr` | 标准错误输出 |
-
-### 10.2. 重定向
-
-重定向让我们可以控制一个命令的输入来自哪里,输出结果到什么地方。这些运算符在控制流的重定向时会被用到:
-
-| Operator | Description |
-| -------- | ------------------------------------------------------------- |
-| `>` | 重定向输出 |
-| `&>` | 重定向输出和错误输出 |
-| `&>>` | 以附加的形式重定向输出和错误输出 |
-| `<` | 重定向输入 |
-| `<<` | [Here 文档](http://tldp.org/LDP/abs/html/here-docs.html) 语法 |
-| `<<<` | [Here 字符串](http://www.tldp.org/LDP/abs/html/x17837.html) |
-
-以下是一些使用重定向的例子:
-
-```bash
-### ls的结果将会被写到list.txt中
-ls -l > list.txt
-
-### 将输出附加到list.txt中
-ls -a >> list.txt
-
-### 所有的错误信息会被写到errors.txt中
-grep da * 2> errors.txt
-
-### 从errors.txt中读取输入
-less < errors.txt
-```
-
-### 10.3. `/dev/null` 文件
-
-如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:
-
-```bash
-$ command > /dev/null
-```
-
-/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。
-
-如果希望屏蔽 stdout 和 stderr,可以这样写:
-
-```bash
-$ command > /dev/null 2>&1
-```
-
-## 11. Debug
-
-shell 提供了用于 debug 脚本的工具。
-
-如果想采用 debug 模式运行某脚本,可以在其 shebang 中使用一个特殊的选项:
-
-```
-#!/bin/bash options
-```
-
-options 是一些可以改变 shell 行为的选项。下表是一些可能对你有用的选项:
-
-| Short | Name | Description |
-| ----- | ----------- | ---------------------------------------------------------- |
-| `-f` | noglob | 禁止文件名展开(globbing) |
-| `-i` | interactive | 让脚本以 _交互_ 模式运行 |
-| `-n` | noexec | 读取命令,但不执行(语法检查) |
-| `-t` | — | 执行完第一条命令后退出 |
-| `-v` | verbose | 在执行每条命令前,向`stderr`输出该命令 |
-| `-x` | xtrace | 在执行每条命令前,向`stderr`输出该命令以及该命令的扩展参数 |
-
-举个例子,如果我们在脚本中指定了`-x`例如:
-
-```bash
-#!/bin/bash -x
-
-for (( i = 0; i < 3; i++ )); do
- echo $i
-done
-```
-
-这会向`stdout`打印出变量的值和一些其它有用的信息:
-
-```bash
-$ ./my_script
-+ (( i = 0 ))
-+ (( i < 3 ))
-+ echo 0
-0
-+ (( i++ ))
-+ (( i < 3 ))
-+ echo 1
-1
-+ (( i++ ))
-+ (( i < 3 ))
-+ echo 2
-2
-+ (( i++ ))
-+ (( i < 3 ))
-```
-
-有时我们值需要 debug 脚本的一部分。这种情况下,使用`set`命令会很方便。这个命令可以启用或禁用选项。使用`-`启用选项,`+`禁用选项:
-
-**:keyboard: 『示例源码』** [debug-demo.sh](https://github.com/dunwu/linux-tutorial/blob/master/codes/shell/demos/debug-demo.sh)
-
-```bash
-# 开启 debug
-set -x
-for (( i = 0; i < 3; i++ )); do
- printf ${i}
-done
-# 关闭 debug
-set +x
-# Output:
-# + (( i = 0 ))
-# + (( i < 3 ))
-# + printf 0
-# 0+ (( i++ ))
-# + (( i < 3 ))
-# + printf 1
-# 1+ (( i++ ))
-# + (( i < 3 ))
-# + printf 2
-# 2+ (( i++ ))
-# + (( i < 3 ))
-# + set +x
-
-for i in {1..5}; do printf ${i}; done
-printf "\n"
-# Output: 12345
-```
-
-## 12. 更多内容
-
-> :notebook: 本文已归档到:「[blog](https://github.com/dunwu/blog)」
-
-- [awesome-shell](https://github.com/alebcay/awesome-shell),shell 资源列表
-- [awesome-bash](https://github.com/awesome-lists/awesome-bash),bash 资源列表
-- [bash-handbook](https://github.com/denysdovhan/bash-handbook)
-- [bash-guide](https://github.com/vuuihc/bash-guide) ,bash 基本用法指南
-- [bash-it](https://github.com/Bash-it/bash-it),为你日常使用,开发以及维护 shell 脚本和自定义命令提供了一个可靠的框架
-- [dotfiles.github.io](http://dotfiles.github.io/),上面有 bash 和其它 shell 的各种 dotfiles 集合以及 shell 框架的链接
-- [Runoob Shell 教程](http://www.runoob.com/linux/linux-shell.html)
-- [shellcheck](https://github.com/koalaman/shellcheck) 一个静态 shell 脚本分析工具,本质上是 bash/sh/zsh 的 lint。
-
-最后,Stack Overflow 上 [bash 标签下](https://stackoverflow.com/questions/tagged/bash)有很多你可以学习的问题,当你遇到问题时,也是一个提问的好地方。
diff --git a/docs/linux/ops/systemd.md b/docs/linux/ops/systemd.md
new file mode 100644
index 00000000..a7f9d73d
--- /dev/null
+++ b/docs/linux/ops/systemd.md
@@ -0,0 +1,966 @@
+# Systemd 应用
+
+> 搬运自:[Systemd 入门教程:命令篇](http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html)、[Systemd 入门教程:实战篇](hhttp://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html)
+
+Systemd 是 Linux 系统工具,用来启动[守护进程](http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html),已成为大多数发行版的标准配置。
+
+本文介绍它的基本用法,分为上下两篇。今天介绍它的主要命令,[下一篇](http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html)介绍如何用于实战。
+
+## 1. 由来
+
+历史上,[Linux 的启动](http://www.ruanyifeng.com/blog/2013/08/linux_boot_process.html)一直采用[`init`](https://en.wikipedia.org/wiki/Init)进程。
+
+下面的命令用来启动服务。
+
+```bash
+$ sudo /etc/init.d/apache2 start
+# 或者
+$ service apache2 start
+```
+
+这种方法有两个缺点。
+
+一是启动时间长。`init`进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
+
+二是启动脚本复杂。`init`进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种
+情况,这往往使得脚本变得很长。
+
+## 2. Systemd 概述
+
+Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套
+完整的解决方案。
+
+根据 Linux 惯例,字母`d`是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就
+是它要守护整个系统。
+
+使用了 Systemd,就不需要再用`init`了。Systemd 取代了`initd`,成为系统的第一个进
+程(PID 等于 1),其他进程都是它的子进程。
+
+```bash
+$ systemctl --version
+```
+
+上面的命令查看 Systemd 的版本。
+
+Systemd 的优点是功能强大,使用方便,缺点是体系庞大,非常复杂。事实上,现在还有很
+多人反对使用 Systemd,理由就是它过于复杂,与操作系统的其他部分强耦合,违反"keep
+simple, keep stupid"
+的[Unix 哲学](http://www.ruanyifeng.com/blog/2009/06/unix_philosophy.html)。
+
+
+
+(上图为 Systemd 架构图)
+
+## 3. 系统管理
+
+Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。
+
+### 3.1. systemctl
+
+`systemctl`是 Systemd 的主命令,用于管理系统。
+
+```bash
+# 重启系统
+$ sudo systemctl reboot
+
+# 关闭系统,切断电源
+$ sudo systemctl poweroff
+
+# CPU停止工作
+$ sudo systemctl halt
+
+# 暂停系统
+$ sudo systemctl suspend
+
+# 让系统进入冬眠状态
+$ sudo systemctl hibernate
+
+# 让系统进入交互式休眠状态
+$ sudo systemctl hybrid-sleep
+
+# 启动进入救援状态(单用户状态)
+$ sudo systemctl rescue
+```
+
+### 3.2. systemd-analyze
+
+`systemd-analyze`命令用于查看启动耗时。
+
+```bash
+# 查看启动耗时
+$ systemd-analyze
+
+# 查看每个服务的启动耗时
+$ systemd-analyze blame
+
+# 显示瀑布状的启动过程流
+$ systemd-analyze critical-chain
+
+# 显示指定服务的启动流
+$ systemd-analyze critical-chain atd.service
+```
+
+### 3.3. hostnamectl
+
+`hostnamectl`命令用于查看当前主机的信息。
+
+```bash
+# 显示当前主机的信息
+$ hostnamectl
+
+# 设置主机名。
+$ sudo hostnamectl set-hostname rhel7
+```
+
+### 3.4. localectl
+
+`localectl`命令用于查看本地化设置。
+
+```bash
+# 查看本地化设置
+$ localectl
+
+# 设置本地化参数。
+$ sudo localectl set-locale LANG=en_GB.utf8
+$ sudo localectl set-keymap en_GB
+```
+
+### 3.5. timedatectl
+
+`timedatectl`命令用于查看当前时区设置。
+
+```bash
+# 查看当前时区设置
+$ timedatectl
+
+# 显示所有可用的时区
+$ timedatectl list-timezones
+
+# 设置当前时区
+$ sudo timedatectl set-timezone America/New_York
+$ sudo timedatectl set-time YYYY-MM-DD
+$ sudo timedatectl set-time HH:MM:SS
+```
+
+### 3.6. loginctl
+
+`loginctl`命令用于查看当前登录的用户。
+
+```bash
+# 列出当前session
+$ loginctl list-sessions
+
+# 列出当前登录用户
+$ loginctl list-users
+
+# 列出显示指定用户的信息
+$ loginctl show-user ruanyf
+```
+
+## 4. Unit
+
+### 4.1. 含义
+
+Systemd 可以管理所有系统资源。不同的资源统称为 Unit(单位)。
+
+Unit 一共分成 12 种。
+
+- Service unit:系统服务
+- Target unit:多个 Unit 构成的一个组
+- Device Unit:硬件设备
+- Mount Unit:文件系统的挂载点
+- Automount Unit:自动挂载点
+- Path Unit:文件或路径
+- Scope Unit:不是由 Systemd 启动的外部进程
+- Slice Unit:进程组
+- Snapshot Unit:Systemd 快照,可以切回某个快照
+- Socket Unit:进程间通信的 socket
+- Swap Unit:swap 文件
+- Timer Unit:定时器
+
+`systemctl list-units`命令可以查看当前系统的所有 Unit 。
+
+```bash
+# 列出正在运行的 Unit
+$ systemctl list-units
+
+# 列出所有Unit,包括没有找到配置文件的或者启动失败的
+$ systemctl list-units --all
+
+# 列出所有没有运行的 Unit
+$ systemctl list-units --all --state=inactive
+
+# 列出所有加载失败的 Unit
+$ systemctl list-units --failed
+
+# 列出所有正在运行的、类型为 service 的 Unit
+$ systemctl list-units --type=service
+```
+
+### 4.2. Unit 的状态
+
+`systemctl status`命令用于查看系统状态和单个 Unit 的状态。
+
+```bash
+# 显示系统状态
+$ systemctl status
+
+# 显示单个 Unit 的状态
+$ sysystemctl status bluetooth.service
+
+# 显示远程主机的某个 Unit 的状态
+$ systemctl -H root@rhel7.example.com status httpd.service
+```
+
+除了`status`命令,`systemctl`还提供了三个查询状态的简单方法,主要供脚本内部的判
+断语句使用。
+
+```bash
+# 显示某个 Unit 是否正在运行
+$ systemctl is-active application.service
+
+# 显示某个 Unit 是否处于启动失败状态
+$ systemctl is-failed application.service
+
+# 显示某个 Unit 服务是否建立了启动链接
+$ systemctl is-enabled application.service
+```
+
+### 4.3. Unit 管理
+
+对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service)。
+
+```bash
+# 立即启动一个服务
+$ sudo systemctl start apache.service
+
+# 立即停止一个服务
+$ sudo systemctl stop apache.service
+
+# 重启一个服务
+$ sudo systemctl restart apache.service
+
+# 杀死一个服务的所有子进程
+$ sudo systemctl kill apache.service
+
+# 重新加载一个服务的配置文件
+$ sudo systemctl reload apache.service
+
+# 重载所有修改过的配置文件
+$ sudo systemctl daemon-reload
+
+# 显示某个 Unit 的所有底层参数
+$ systemctl show httpd.service
+
+# 显示某个 Unit 的指定属性的值
+$ systemctl show -p CPUShares httpd.service
+
+# 设置某个 Unit 的指定属性
+$ sudo systemctl set-property httpd.service CPUShares=500
+```
+
+### 4.4. 依赖关系
+
+Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启
+动 B。
+
+`systemctl list-dependencies`命令列出一个 Unit 的所有依赖。
+
+```bash
+$ systemctl list-dependencies nginx.service
+```
+
+上面命令的输出结果之中,有些依赖是 Target 类型(详见下文),默认不会展开显示。如
+果要展开 Target,就需要使用`--all`参数。
+
+```bash
+$ systemctl list-dependencies --all nginx.service
+```
+
+## 5. Unit 的配置文件
+
+### 5.1. 概述
+
+每一个 Unit 都有一个配置文件,告诉 Systemd 怎么启动这个 Unit 。
+
+Systemd 默认从目录`/etc/systemd/system/`读取配置文件。但是,里面存放的大部分文件
+都是符号链接,指向目录`/usr/lib/systemd/system/`,真正的配置文件存放在那个目录。
+
+`systemctl enable`命令用于在上面两个目录之间,建立符号链接关系。
+
+```bash
+$ sudo systemctl enable clamd@scan.service
+# 等同于
+$ sudo ln -s '/usr/lib/systemd/system/clamd@scan.service' '/etc/systemd/system/multi-user.target.wants/clamd@scan.service'
+```
+
+如果配置文件里面设置了开机启动,`systemctl enable`命令相当于激活开机启动。
+
+与之对应的,`systemctl disable`命令用于在两个目录之间,撤销符号链接关系,相当于
+撤销开机启动。
+
+```bash
+$ sudo systemctl disable clamd@scan.service
+```
+
+配置文件的后缀名,就是该 Unit 的种类,比如`sshd.socket`。如果省略,Systemd 默认
+后缀名为`.service`,所以`sshd`会被理解成`sshd.service`。
+
+### 5.2. 配置文件的状态
+
+`systemctl list-unit-files`命令用于列出所有配置文件。
+
+```bash
+# 列出所有配置文件
+$ systemctl list-unit-files
+
+# 列出指定类型的配置文件
+$ systemctl list-unit-files --type=service
+```
+
+这个命令会输出一个列表。
+
+```bash
+$ systemctl list-unit-files
+
+UNIT FILE STATE
+chronyd.service enabled
+clamd@.service static
+clamd@scan.service disabled
+```
+
+这个列表显示每个配置文件的状态,一共有四种。
+
+- enabled:已建立启动链接
+- disabled:没建立启动链接
+- static:该配置文件没有`[Install]`部分(无法执行),只能作为其他配置文件的依赖
+- masked:该配置文件被禁止建立启动链接
+
+注意,从配置文件的状态无法看出,该 Unit 是否正在运行。这必须执行前面提到
+的`systemctl status`命令。
+
+```bash
+$ systemctl status bluetooth.service
+```
+
+一旦修改配置文件,就要让 SystemD 重新加载配置文件,然后重新启动,否则修改不会生
+效。
+
+```bash
+$ sudo systemctl daemon-reload
+$ sudo systemctl restart httpd.service
+```
+
+### 5.3. 配置文件的格式
+
+配置文件就是普通的文本文件,可以用文本编辑器打开。
+
+`systemctl cat`命令可以查看配置文件的内容。
+
+```bash
+$ systemctl cat atd.service
+
+[Unit]
+Description=ATD daemon
+
+[Service]
+Type=forking
+ExecStart=/usr/bin/atd
+
+[Install]
+WantedBy=multi-user.target
+```
+
+从上面的输出可以看到,配置文件分成几个区块。每个区块的第一行,是用方括号表示的区
+别名,比如`[Unit]`。注意,配置文件的区块名和字段名,都是大小写敏感的。
+
+每个区块内部是一些等号连接的键值对。
+
+```bash
+[Section]
+Directive1=value
+Directive2=value
+
+. . .
+```
+
+注意,键值对的等号两侧不能有空格。
+
+### 5.4. 配置文件的区块
+
+`[Unit]`区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他
+Unit 的关系。它的主要字段如下。
+
+- `Description`:简短描述
+- `Documentation`:文档地址
+- `Requires`:当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败
+- `Wants`:与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败
+- `BindsTo`:与`Requires`类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行
+- `Before`:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动
+- `After`:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动
+- `Conflicts`:这里指定的 Unit 不能与当前 Unit 同时运行
+- `Condition...`:当前 Unit 运行必须满足的条件,否则不会运行
+- `Assert...`:当前 Unit 运行必须满足的条件,否则会报启动失败
+
+`[Install]`通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。它
+的主要字段如下。
+
+- `WantedBy`:它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放
+ 入`/etc/systemd/system`目录下面以 Target 名 + `.wants`后缀构成的子目录中
+- `RequiredBy`:它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放
+ 入`/etc/systemd/system`目录下面以 Target 名 + `.required`后缀构成的子目录中
+- `Alias`:当前 Unit 可用于启动的别名
+- `Also`:当前 Unit 激活(enable)时,会被同时激活的其他 Unit
+
+`[Service]`区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。它的
+主要字段如下。
+
+- `Type`:定义启动时的进程行为。它有以下几种值。
+- `Type=simple`:默认值,执行`ExecStart`指定的命令,启动主进程
+- `Type=forking`:以 fork 方式从父进程创建子进程,创建后父进程会立即退出
+- `Type=oneshot`:一次性进程,Systemd 会等当前服务退出,再继续往下执行
+- `Type=dbus`:当前服务通过 D-Bus 启动
+- `Type=notify`:当前服务启动完毕,会通知`Systemd`,再继续往下执行
+- `Type=idle`:若有其他任务执行完毕,当前服务才会运行
+- `ExecStart`:启动当前服务的命令
+- `ExecStartPre`:启动当前服务之前执行的命令
+- `ExecStartPost`:启动当前服务之后执行的命令
+- `ExecReload`:重启当前服务时执行的命令
+- `ExecStop`:停止当前服务时执行的命令
+- `ExecStopPost`:停止当其服务之后执行的命令
+- `RestartSec`:自动重启当前服务间隔的秒数
+- `Restart`:定义何种情况 Systemd 会自动重启当前服务,可能的值包括`always`(总是
+ 重启)、`on-success`、`on-failure`、`on-abnormal`、`on-abort`、`on-watchdog`
+- `TimeoutSec`:定义 Systemd 停止当前服务之前等待的秒数
+- `Environment`:指定环境变量
+
+Unit 配置文件的完整字段清单,请参
+考[官方文档](https://www.freedesktop.org/software/systemd/man/systemd.unit.html)。
+
+## 6. Target
+
+启动计算机的时候,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要
+哪些 Unit,显然非常不方便。Systemd 的解决方案就是 Target。
+
+简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候
+,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于"状态点
+",启动某个 Target 就好比启动到某种状态。
+
+传统的`init`启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是
+,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动
+。
+
+```bash
+# 查看当前系统的所有 Target
+$ systemctl list-unit-files --type=target
+
+# 查看一个 Target 包含的所有 Unit
+$ systemctl list-dependencies multi-user.target
+
+# 查看启动时的默认 Target
+$ systemctl get-default
+
+# 设置启动时的默认 Target
+$ sudo systemctl set-default multi-user.target
+
+# 切换 Target 时,默认不关闭前一个 Target 启动的进程,
+# systemctl isolate 命令改变这种行为,
+# 关闭前一个 Target 里面所有不属于后一个 Target 的进程
+$ sudo systemctl isolate multi-user.target
+```
+
+Target 与 传统 RunLevel 的对应关系如下。
+
+```bash
+Traditional runlevel New target name Symbolically linked to...
+
+Runlevel 0 | runlevel0.target -> poweroff.target
+Runlevel 1 | runlevel1.target -> rescue.target
+Runlevel 2 | runlevel2.target -> multi-user.target
+Runlevel 3 | runlevel3.target -> multi-user.target
+Runlevel 4 | runlevel4.target -> multi-user.target
+Runlevel 5 | runlevel5.target -> graphical.target
+Runlevel 6 | runlevel6.target -> reboot.target
+```
+
+它与`init`进程的主要差别如下。
+
+**(1)默认的 RunLevel**(在`/etc/inittab`文件设置)现在被默认的 Target 取代,
+位置是`/etc/systemd/system/default.target`,通常符号链接到`graphical.target`(
+图形界面)或者`multi-user.target`(多用户命令行)。
+
+**(2)启动脚本的位置**,以前是`/etc/init.d`目录,符号链接到不同的 RunLevel 目
+录 (比如`/etc/rc3.d`、`/etc/rc5.d`等),现在则存放
+在`/lib/systemd/system`和`/etc/systemd/system`目录。
+
+**(3)配置文件的位置**,以前`init`进程的配置文件是`/etc/inittab`,各种服务的
+配置文件存放在`/etc/sysconfig`目录。现在的配置文件主要存放在`/lib/systemd`目录
+,在`/etc/systemd`目录里面的修改可以覆盖原始设置。
+
+## 7. 日志管理
+
+Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用`journalctl`一个命
+令,查看所有日志(内核日志和应用日志)。日志的配置文件
+是`/etc/systemd/journald.conf`。
+
+`journalctl`功能强大,用法非常多。
+
+```bash
+# 查看所有日志(默认情况下 ,只保存本次启动的日志)
+$ sudo journalctl
+
+# 查看内核日志(不显示应用日志)
+$ sudo journalctl -k
+
+# 查看系统本次启动的日志
+$ sudo journalctl -b
+$ sudo journalctl -b -0
+
+# 查看上一次启动的日志(需更改设置)
+$ sudo journalctl -b -1
+
+# 查看指定时间的日志
+$ sudo journalctl --since="2012-10-30 18:17:16"
+$ sudo journalctl --since "20 min ago"
+$ sudo journalctl --since yesterday
+$ sudo journalctl --since "2015-01-10" --until "2015-01-11 03:00"
+$ sudo journalctl --since 09:00 --until "1 hour ago"
+
+# 显示尾部的最新10行日志
+$ sudo journalctl -n
+
+# 显示尾部指定行数的日志
+$ sudo journalctl -n 20
+
+# 实时滚动显示最新日志
+$ sudo journalctl -f
+
+# 查看指定服务的日志
+$ sudo journalctl /usr/lib/systemd/systemd
+
+# 查看指定进程的日志
+$ sudo journalctl _PID=1
+
+# 查看某个路径的脚本的日志
+$ sudo journalctl /usr/bin/bash
+
+# 查看指定用户的日志
+$ sudo journalctl _UID=33 --since today
+
+# 查看某个 Unit 的日志
+$ sudo journalctl -u nginx.service
+$ sudo journalctl -u nginx.service --since today
+
+# 实时滚动显示某个 Unit 的最新日志
+$ sudo journalctl -u nginx.service -f
+
+# 合并显示多个 Unit 的日志
+$ journalctl -u nginx.service -u php-fpm.service --since today
+
+# 查看指定优先级(及其以上级别)的日志,共有8级
+# 0: emerg
+# 1: alert
+# 2: crit
+# 3: err
+# 4: warning
+# 5: notice
+# 6: info
+# 7: debug
+$ sudo journalctl -p err -b
+
+# 日志默认分页输出,--no-pager 改为正常的标准输出
+$ sudo journalctl --no-pager
+
+# 以 JSON 格式(单行)输出
+$ sudo journalctl -b -u nginx.service -o json
+
+# 以 JSON 格式(多行)输出,可读性更好
+$ sudo journalctl -b -u nginx.serviceqq
+ -o json-pretty
+
+# 显示日志占据的硬盘空间
+$ sudo journalctl --disk-usage
+
+# 指定日志文件占据的最大空间
+$ sudo journalctl --vacuum-size=1G
+
+# 指定日志文件保存多久
+$ sudo journalctl --vacuum-time=1years
+```
+
+## 8. 实战
+
+### 8.1. 开机启动
+
+对于那些支持 Systemd 的软件,安装的时候,会自动在`/usr/lib/systemd/system`目录添
+加一个配置文件。
+
+如果你想让该软件开机启动,就执行下面的命令(以`httpd.service`为例)。
+
+```bash
+$ sudo systemctl enable httpd
+```
+
+上面的命令相当于在`/etc/systemd/system`目录添加一个符号链接,指
+向`/usr/lib/systemd/system`里面的`httpd.service`文件。
+
+这是因为开机时,`Systemd`只执行`/etc/systemd/system`目录里面的配置文件。这也意味
+着,如果把修改后的配置文件放在该目录,就可以达到覆盖原始配置的效果。
+
+### 8.2. 启动服务
+
+设置开机启动以后,软件并不会立即启动,必须等到下一次开机。如果想现在就运行该软件
+,那么要执行`systemctl start`命令。
+
+```bash
+$ sudo systemctl start httpd
+```
+
+执行上面的命令以后,有可能启动失败,因此要用`systemctl status`命令查看一下该服务
+的状态。
+
+```bash
+$ sudo systemctl status httpd
+
+httpd.service - The Apache HTTP Server
+Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled)
+Active: active (running) since 金 2014-12-05 12:18:22 JST; 7min ago
+Main PID: 4349 (httpd)
+Status: "Total requests: 1; Current requests/sec: 0; Current traffic: 0 B/sec"
+CGroup: /system.slice/httpd.service
+ ├─4349 /usr/sbin/httpd -DFOREGROUND
+ ├─4350 /usr/sbin/httpd -DFOREGROUND
+ ├─4351 /usr/sbin/httpd -DFOREGROUND
+ ├─4352 /usr/sbin/httpd -DFOREGROUND
+ ├─4353 /usr/sbin/httpd -DFOREGROUND
+ └─4354 /usr/sbin/httpd -DFOREGROUND
+
+12月 05 12:18:22 localhost.localdomain systemd[1]: Starting The Apache HTTP Server...
+12月 05 12:18:22 localhost.localdomain systemd[1]: Started The Apache HTTP Server.
+12月 05 12:22:40 localhost.localdomain systemd[1]: Started The Apache HTTP Server.
+```
+
+上面的输出结果含义如下。
+
+- `Loaded`行:配置文件的位置,是否设为开机启动
+- `Active`行:表示正在运行
+- `Main PID`行:主进程 ID
+- `Status`行:由应用本身(这里是 httpd )提供的软件当前状态
+- `CGroup`块:应用的所有子进程
+- 日志块:应用的日志
+
+### 8.3. 停止服务
+
+终止正在运行的服务,需要执行`systemctl stop`命令。
+
+```bash
+$ sudo systemctl stop httpd.service
+```
+
+有时候,该命令可能没有响应,服务停不下来。这时候就不得不"杀进程"了,向正在运行的
+进程发出`kill`信号。
+
+```bash
+$ sudo systemctl kill httpd.service
+```
+
+此外,重启服务要执行`systemctl restart`命令。
+
+```bash
+$ sudo systemctl restart httpd.service
+```
+
+### 8.4. 读懂配置文件
+
+一个服务怎么启动,完全由它的配置文件决定。下面就来看,配置文件有些什么内容。
+
+前面说过,配置文件主要放在`/usr/lib/systemd/system`目录,也可能
+在`/etc/systemd/system`目录。找到配置文件以后,使用文本编辑器打开即可。
+
+`systemctl cat`命令可以用来查看配置文件,下面以`sshd.service`文件为例,它的作用
+是启动一个 SSH 服务器,供其他用户以 SSH 方式登录。
+
+```
+$ systemctl cat sshd.service
+
+[Unit]
+Description=OpenSSH server daemon
+Documentation=man:sshd(8) man:sshd_config(5)
+After=network.target sshd-keygen.service
+Wants=sshd-keygen.service
+
+[Service]
+EnvironmentFile=/etc/sysconfig/sshd
+ExecStart=/usr/sbin/sshd -D $OPTIONS
+ExecReload=/bin/kill -HUP $MAINPID
+Type=simple
+KillMode=process
+Restart=on-failure
+RestartSec=42s
+
+[Install]
+WantedBy=multi-user.target
+```
+
+可以看到,配置文件分成几个区块,每个区块包含若干条键值对。
+
+下面依次解释每个区块的内容。
+
+### 8.5. [Unit] 区块:启动顺序与依赖关系。
+
+`Unit`区块的`Description`字段给出当前服务的简单描述,`Documentation`字段给出文档
+位置。
+
+接下来的设置是启动顺序和依赖关系,这个比较重要。
+
+> `After`字段:表示如果`network.target`或`sshd-keygen.service`需要启动,那
+> 么`sshd.service`应该在它们之后启动。
+
+相应地,还有一个`Before`字段,定义`sshd.service`应该在哪些服务之前启动。
+
+注意,`After`和`Before`字段只涉及启动顺序,不涉及依赖关系。
+
+举例来说,某 Web 应用需要 postgresql 数据库储存数据。在配置文件中,它只定义要在
+postgresql 之后启动,而没有定义依赖 postgresql 。上线后,由于某种原因
+,postgresql 需要重新启动,在停止服务期间,该 Web 应用就会无法建立数据库连接。
+
+设置依赖关系,需要使用`Wants`字段和`Requires`字段。
+
+> `Wants`字段:表示`sshd.service`与`sshd-keygen.service`之间存在"弱依赖"关系,即
+> 如果"sshd-keygen.service"启动失败或停止运行,不影响`sshd.service`继续执行。
+
+`Requires`字段则表示"强依赖"关系,即如果该服务启动失败或异常退出,那
+么`sshd.service`也必须退出。
+
+注意,`Wants`字段与`Requires`字段只涉及依赖关系,与启动顺序无关,默认情况下是同
+时启动的。
+
+### 8.6. [Service] 区块:启动行为
+
+`Service`区块定义如何启动当前服务。
+
+#### 8.6.1. 启动命令
+
+许多软件都有自己的环境参数文件,该文件可以用`EnvironmentFile`字段读取。
+
+> `EnvironmentFile`字段:指定当前服务的环境参数文件。该文件内部的`key=value`键值
+> 对,可以用`$key`的形式,在当前配置文件中获取。
+
+上面的例子中,sshd 的环境参数文件是`/etc/sysconfig/sshd`。
+
+配置文件里面最重要的字段是`ExecStart`。
+
+> `ExecStart`字段:定义启动进程时执行的命令。
+
+上面的例子中,启动`sshd`,执行的命令是`/usr/sbin/sshd -D $OPTIONS`,其中的变
+量`$OPTIONS`就来自`EnvironmentFile`字段指定的环境参数文件。
+
+与之作用相似的,还有如下这些字段。
+
+- `ExecReload`字段:重启服务时执行的命令
+- `ExecStop`字段:停止服务时执行的命令
+- `ExecStartPre`字段:启动服务之前执行的命令
+- `ExecStartPost`字段:启动服务之后执行的命令
+- `ExecStopPost`字段:停止服务之后执行的命令
+
+请看下面的例子。
+
+```
+[Service]
+ExecStart=/bin/echo execstart1
+ExecStart=
+ExecStart=/bin/echo execstart2
+ExecStartPost=/bin/echo post1
+ExecStartPost=/bin/echo post2
+```
+
+上面这个配置文件,第二行`ExecStart`设为空值,等于取消了第一行的设置,运行结果如
+下。
+
+```
+execstart2
+post1
+post2
+```
+
+所有的启动设置之前,都可以加上一个连词号(`-`),表示"抑制错误",即发生错误的时
+候,不影响其他命令的执行。比如,`EnvironmentFile=-/etc/sysconfig/sshd`(注意等号
+后面的那个连词号),就表示即使`/etc/sysconfig/sshd`文件不存在,也不会抛出错误。
+
+#### 8.6.2. 启动类型
+
+`Type`字段定义启动类型。它可以设置的值如下。
+
+- simple(默认值):`ExecStart`字段启动的进程为主进程
+- forking:`ExecStart`字段将以`fork()`方式启动,此时父进程将会退出,子进程将成
+ 为主进程
+- oneshot:类似于`simple`,但只执行一次,Systemd 会等它执行完,才启动其他服务
+- dbus:类似于`simple`,但会等待 D-Bus 信号后启动
+- notify:类似于`simple`,启动结束后会发出通知信号,然后 Systemd 再启动其他服
+ 务
+- idle:类似于`simple`,但是要等到其他任务都执行完,才会启动该服务。一种使用场
+ 合是为让该服务的输出,不与其他服务的输出相混合
+
+下面是一个`oneshot`的例子,笔记本电脑启动时,要把触摸板关掉,配置文件可以这样写
+。
+
+```
+[Unit]
+Description=Switch-off Touchpad
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/touchpad-off
+
+[Install]
+WantedBy=multi-user.target
+```
+
+上面的配置文件,启动类型设为`oneshot`,就表明这个服务只要运行一次就够了,不需要
+长期运行。
+
+如果关闭以后,将来某个时候还想打开,配置文件修改如下。
+
+```
+[Unit]
+Description=Switch-off Touchpad
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/touchpad-off start
+ExecStop=/usr/bin/touchpad-off stop
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
+```
+
+上面配置文件中,`RemainAfterExit`字段设为`yes`,表示进程退出以后,服务仍然保持执
+行。这样的话,一旦使用`systemctl stop`命令停止服务,`ExecStop`指定的命令就会执行
+,从而重新开启触摸板。
+
+#### 8.6.3. 重启行为
+
+`Service`区块有一些字段,定义了重启行为。
+
+> `KillMode`字段:定义 Systemd 如何停止 sshd 服务。
+
+上面这个例子中,将`KillMode`设为`process`,表示只停止主进程,不停止任何 sshd 子
+进程,即子进程打开的 SSH session 仍然保持连接。这个设置不太常见,但对 sshd 很重
+要,否则你停止服务的时候,会连自己打开的 SSH session 一起杀掉。
+
+`KillMode`字段可以设置的值如下。
+
+- control-group(默认值):当前控制组里面的所有子进程,都会被杀掉
+- process:只杀主进程
+- mixed:主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号
+- none:没有进程会被杀掉,只是执行服务的 stop 命令。
+
+接下来是`Restart`字段。
+
+> `Restart`字段:定义了 sshd 退出后,Systemd 的重启方式。
+
+上面的例子中,`Restart`设为`on-failure`,表示任何意外的失败,就将重启 sshd。如果
+sshd 正常停止(比如执行`systemctl stop`命令),它就不会重启。
+
+`Restart`字段可以设置的值如下。
+
+- no(默认值):退出后不会重启
+- on-success:只有正常退出时(退出状态码为 0),才会重启
+- on-failure:非正常退出时(退出状态码非 0),包括被信号终止和超时,才会重启
+- on-abnormal:只有被信号终止和超时,才会重启
+- on-abort:只有在收到没有捕捉到的信号终止时,才会重启
+- on-watchdog:超时退出,才会重启
+- always:不管是什么退出原因,总是重启
+
+对于守护进程,推荐设为`on-failure`。对于那些允许发生错误退出的服务,可以设
+为`on-abnormal`。
+
+最后是`RestartSec`字段。
+
+> `RestartSec`字段:表示 Systemd 重启服务之前,需要等待的秒数。上面的例子设为等
+> 待 42 秒。
+
+### 8.7. [Install] 区块
+
+`Install`区块,定义如何安装这个配置文件,即怎样做到开机启动。
+
+`WantedBy`字段:表示该服务所在的 Target。
+
+`Target`的含义是服务组,表示一组服务。`WantedBy=multi-user.target`指的是,sshd
+所在的 Target 是`multi-user.target`。
+
+这个设置非常重要,因为执行`systemctl enable sshd.service`命令时
+,`sshd.service`的一个符号链接,就会放在`/etc/systemd/system`目录下面
+的`multi-user.target.wants`子目录之中。
+
+Systemd 有默认的启动 Target。
+
+```bash
+$ systemctl get-default
+multi-user.target
+```
+
+上面的结果表示,默认的启动 Target 是`multi-user.target`。在这个组里的所有服务,
+都将开机启动。这就是为什么`systemctl enable`命令能设置开机启动的原因。
+
+使用 Target 的时候,`systemctl list-dependencies`命令和`systemctl isolate`命令也
+很有用。
+
+```bash
+# 查看 multi-user.target 包含的所有服务
+$ systemctl list-dependencies multi-user.target
+
+# 切换到另一个 target
+# shutdown.target 就是关机状态
+$ sudo systemctl isolate shutdown.target
+```
+
+一般来说,常用的 Target 有两个:一个是`multi-user.target`,表示多用户命令行状态
+;另一个是`graphical.target`,表示图形用户状态,它依赖于`multi-user.target`。官
+方文档有一张非常清晰的
+[Target 依赖关系图](https://www.freedesktop.org/software/systemd/man/bootup.html#System%20Manager%20Bootup)。
+
+### 8.8. Target 的配置文件
+
+Target 也有自己的配置文件。
+
+```bash
+$ systemctl cat multi-user.target
+
+[Unit]
+Description=Multi-User System
+Documentation=man:systemd.special(7)
+Requires=basic.target
+Conflicts=rescue.service rescue.target
+After=basic.target rescue.service rescue.target
+AllowIsolate=yes
+```
+
+注意,Target 配置文件里面没有启动命令。
+
+上面输出结果中,主要字段含义如下。
+
+- `Requires`字段:要求`basic.target`一起运行。
+- `Conflicts`字段:冲突字段。如果`rescue.service`或`rescue.target`正在运行
+ ,`multi-user.target`就不能运行,反之亦然。
+- `After`:表示`multi-user.target`在`basic.target` 、 `rescue.service`、
+ `rescue.target`之后启动,如果它们有启动的话。
+- `AllowIsolate`:允许使用`systemctl isolate`命令切换到`multi-user.target`。
+
+### 8.9. 修改配置文件后重启
+
+修改配置文件以后,需要重新加载配置文件,然后重新启动相关服务。
+
+```bash
+# 重新加载配置文件
+$ sudo systemctl daemon-reload
+
+# 重启相关服务
+$ sudo systemctl restart foobar
+```
+
+## 9. 参考资料
+
+- [Systemd 入门教程:命令篇](http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html)
+- [Systemd 入门教程:实战篇](hhttp://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html)
diff --git a/docs/linux/ops/vim.md b/docs/linux/ops/vim.md
index 4b658e95..ece7522d 100644
--- a/docs/linux/ops/vim.md
+++ b/docs/linux/ops/vim.md
@@ -1,24 +1,4 @@
-# Vim 应用指南
-
-
-
-- [1. 概念](#1-概念)
- - [1.1. 什么是 vim](#11-什么是-vim)
- - [1.2. Vim 的模式](#12-vim-的模式)
-- [2. Vim 渐进学习](#2-vim-渐进学习)
- - [2.1. 存活](#21-存活)
- - [2.2. 感觉良好](#22-感觉良好)
- - [2.3. 更好,更强,更快](#23-更好更强更快)
- - [2.4. Vim 超能力](#24-vim-超能力)
-- [3. Vim Cheat Sheet](#3-vim-cheat-sheet)
- - [3.1. 经典版](#31-经典版)
- - [3.2. 入门版](#32-入门版)
- - [3.3. 进阶版](#33-进阶版)
- - [3.4. 增强版](#34-增强版)
- - [3.5. 文字版](#35-文字版)
-- [4. 资料](#4-资料)
-
-
+# Vim 应用
## 1. 概念
@@ -30,19 +10,19 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
基本上 vi/vim 共分为三种模式,分别是**命令模式(Command mode)**,**插入模式(Insert mode)**和**底线命令模式(Last line mode)**。
-#### 命令模式
+#### 1.2.1. 命令模式
**用户刚刚启动 vi/vim,便进入了命令模式。**
此状态下敲击键盘动作会被 Vim 识别为命令,而非输入字符。
-#### 插入模式
+#### 1.2.2. 插入模式
**在命令模式下按下 `i` 就进入了输入模式。**
在输入模式下,你可以输入文本内容。
-#### 底线命令模式
+#### 1.2.3. 底线命令模式
**在命令模式下按下 `:`(英文冒号)就进入了底线命令模式。**
@@ -133,7 +113,7 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
先恭喜你!你干的很不错。我们可以开始一些更为有趣的事了。在第三级,我们只谈那些和 vi 可以兼容的命令。
-#### 更好
+#### 2.3.1. 更好
下面,让我们看一下 vim 是怎么重复自己的:1515G
@@ -148,7 +128,7 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
> - `.` → 重复上一个命令—— 100 “desu “.
> - `3.` → 重复 3 次 “desu” (注意:不是 300,你看,VIM 多聪明啊).
-#### 更强
+#### 2.3.2. 更强
你要让你的光标移动更有效率,你一定要了解下面的这些命令,**千万别跳过**。
@@ -167,7 +147,7 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
>
> \> 如果你认为单词是由 blank 字符分隔符,那么你需要使用大写的 E 和 W。(注:程序语句)
>
-
+ > 
下面,让我来说说最强的光标移动:
@@ -176,7 +156,7 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
相信我,上面这三个命令对程序员来说是相当强大的。
-#### 更快
+#### 2.3.3. 更快
你一定要记住光标的移动,因为很多命令都可以和这些移动光标的命令连动。很多命令都可以如下来干:
@@ -206,7 +186,7 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
你只需要掌握前面的命令,你就可以很舒服的使用 VIM 了。但是,现在,我们向你介绍的是 VIM 杀手级的功能。下面这些功能是我只用 vim 的原因。
-#### 在当前行上移动光标: `0` `^` `####`f`F`t`T`,``;`
+#### 2.4.1. 在当前行上移动光标: `0` `^` `####`f`F`t`T`,``;`
> - `0` → 到行头
> - `^` → 到本行的第一个非 blank 字符
@@ -216,11 +196,11 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
> - `t,` → 到逗号前的第一个字符。逗号可以变成其它字符。
> - `3fa` → 在当前行查找第三个出现的 a。
> - `F` 和 `T` → 和 `f` 和 `t` 一样,只不过是相反方向。
-
+> 
还有一个很有用的命令是 `dt"` → 删除所有的内容,直到遇到双引号—— `"。`
-#### 区域选择 `a` 或 `i`
+#### 2.4.2. 区域选择 `a` 或 `i`
在 visual 模式下,这些命令很强大,其命令格式为
@@ -238,9 +218,9 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
> - `v2i)` → 会选择 `map (+) ("foo")`
> - `v2a)` → 会选择 `(map (+) ("foo"))`
-
+
-#### 块操作: ``
+#### 2.4.3. 块操作: ``
块操作,典型的操作: `0 I-- [ESC]`
@@ -249,17 +229,17 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
- `` → 向下移动 (你也可以使用 hjkl 来移动光标,或是使用%,或是别的)
- `I-- [ESC]` → I 是插入,插入“`--`”,按 ESC 键来为每一行生效。
-
+
在 Windows 下的 vim,你需要使用 `` 而不是 `` ,`` 是拷贝剪贴板。
-#### 自动提示: `` 和 ``
+#### 2.4.4. 自动提示: `` 和 ``
在 Insert 模式下,你可以输入一个词的开头,然后按 `或是,自动补齐功能就出现了……`
-
+
-#### 宏录制: `qa` 操作序列 `q`, `@a`, `@@`
+#### 2.4.5. 宏录制: `qa` 操作序列 `q`, `@a`, `@@`
- `qa` 把你的操作记录在寄存器 `a。`
- 于是 `@a` 会 replay 被录制的宏。
@@ -286,9 +266,9 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
>
> - 现在做 `100@@` 会创建新的 100 行,并把数据增加到 103.
-
+
-#### 可视化选择: `v`,`V`,``
+#### 2.4.6. 可视化选择: `v`,`V`,``
前面,我们看到了 ``的示例 (在 Windows 下应该是),我们可以使用 `v` 和 `V`。一但被选好了,你可以做下面的事:
@@ -296,7 +276,7 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
- `<` 或 `>` → 左右缩进
- `=` → 自动给缩进 (注:这个功能相当强大,我太喜欢了)
-
+
在所有被选择的行后加上点东西:
@@ -305,9 +285,9 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
- `$` 到行最后
- `A`, 输入字符串,按 `ESC。`
-
+
-#### 分屏: `:split` 和 `vsplit`.
+#### 2.4.7. 分屏: `:split` 和 `vsplit`.
下面是主要的命令,你可以使用 VIM 的帮助 `:help split`. 你可以参考本站以前的一篇文章[VIM 分屏](https://coolshell.cn/articles/1679.html)。
@@ -316,7 +296,7 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
> - `_` (或 `|`) : 最大化尺寸 (| 垂直分屏)
> - `+` (或 `-`) : 增加尺寸
-
+
## 3. Vim Cheat Sheet
@@ -328,33 +308,33 @@ Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错
此外,[这里](http://blog.ngedit.com/vi-vim-cheat-sheet-sch.gif)还有简体中文版。
-
+
### 3.2. 入门版
基本操作的入门版。[原版出处](https://github.com/ahrencode/Miscellaneous)还有 keynote 版本可供 DIY 以及其他相关有用的 cheatsheet。
-
+
### 3.3. 进阶版
下图是 300DPI 的超清大图,另外[查看原文](http://michael.peopleofhonoronly.com/vim/)还有更多版本:黑白,低分辨率,色盲等
-
+
### 3.4. 增强版
下图是一个更新时间较新的现代版,含有的信息也更丰富。[原文链接](http://vimcheatsheet.com/)
-
+
### 3.5. 文字版
[原文链接](http://tnerual.eriogerg.free.fr/vimqrc.pdf)
-
+
-
+
## 4. 资料
diff --git a/docs/linux/ops/zsh.md b/docs/linux/ops/zsh.md
index a6b54a69..973aad8f 100644
--- a/docs/linux/ops/zsh.md
+++ b/docs/linux/ops/zsh.md
@@ -1,24 +1,10 @@
-# Zsh 应用指南
-
-
-
-- [1. Zsh 简介](#1-zsh-简介)
- - [1.1. Zsh 是什么?](#11-zsh-是什么)
-- [2. Zsh 安装](#2-zsh-安装)
- - [2.1. 环境要求](#21-环境要求)
- - [2.2. 安装 zsh](#22-安装-zsh)
- - [2.3. 安装 oh-my-zsh](#23-安装-oh-my-zsh)
- - [2.4. 配置 oh-my-zsh](#24-配置-oh-my-zsh)
-- [3. 快捷键](#3-快捷键)
-- [4. 参考资料](#4-参考资料)
-
-
+# oh-my-zsh 应用
## 1. Zsh 简介
-### 1.1. Zsh 是什么?
+### 1.1. Zsh 是什么
-使用 Linux 的人都知道:**_Shell_ 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。_Shell_ 既是一种命令语言,又是一种程序设计语言**。
+使用 Linux 的人都知道:***Shell_ 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。_Shell_ 既是一种命令语言,又是一种程序设计语言**。
Shell 的类型有很多种,linux 下默认的是 bash,虽然 bash 的功能已经很强大,但对于以懒惰为美德的程序员来说,bash 的提示功能不够强大,界面也不够炫,并非理想工具。
@@ -61,7 +47,7 @@ wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O -
### 2.4. 配置 oh-my-zsh
-#### 插件
+#### 2.4.1. 插件
> oh-my-zsh 插件太多,不一一列举,请参考:[oh-my-zsh 插件列表](https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins)
@@ -94,7 +80,7 @@ wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O -
- 再执行下这个:`source /etc/profile.d/autojump.sh`
- 编辑配置文件,添加上 autojump 的名字:`vim /root/.zshrc`
-#### 主题
+#### 2.4.2. 主题
> oh-my-zsh 主题太多,不一一列举,请参考:[oh-my-zsh 主题列表](https://github.com/robbyrussell/oh-my-zsh/wiki/Themes)
@@ -109,8 +95,7 @@ wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O -
zsh 效果如下:
-
-
+
## 3. 快捷键
- 呃,这个其实可以不用讲的,你自己用的时候你自己会发现的,各种便捷,特别是用 Tab 多的人一定会有各种惊喜的。
diff --git a/docs/linux/soft/README.md b/docs/linux/soft/README.md
index 80d3683e..b0df7bea 100644
--- a/docs/linux/soft/README.md
+++ b/docs/linux/soft/README.md
@@ -1,15 +1,31 @@
# 软件安装配置
-- [JDK 安装](jdk-install.md)
-- [Elastic 安装](elastic)
-- [Gitlab 安装](kafka-install.md)
-- [Jenkins 安装](jenkins-install.md)
-- [Kafka 安装](kafka-install.md)
-- [Maven 安装](maven-install.md)
-- [Nexus 安装](nexus-install.md)
-- [Nodejs 安装](nodejs-install.md)
-- [RocketMQ 安装](rocketmq-install.md)
-- [Svn 安装](svn-ops.md)
-- [Tomcat 安装](tomcat-install.md)
-- [Zookeeper 安装](zookeeper-install.md)
-- [Nacos 安装](nacos-install.md)
+## 📖 内容
+
+- 开发环境
+ - [JDK 安装](jdk-install.md)
+ - [Maven 安装](maven-install.md)
+ - [Nodejs 安装](nodejs-install.md)
+- 开发工具
+ - [Nexus 运维](nexus-ops.md)
+ - [Gitlab 运维](gitlab-ops.md)
+ - [Jenkins 运维](jenkins-ops.md)
+ - [Svn 运维](svn-ops.md)
+ - [YApi 运维](yapi-ops.md)
+- 中间件服务
+ - [Elastic 运维](elastic)
+ - [RocketMQ 运维](rocketmq-install.md)
+ - [Nacos 运维](nacos-install.md)
+- 服务器
+ - [Nginx 教程](https://github.com/dunwu/nginx-tutorial) 📚
+ - [Tomcat 运维](tomcat-install.md)
+- [数据库](https://github.com/dunwu/db-tutorial) 📚
+ - [Mysql 运维](https://github.com/dunwu/db-tutorial/blob/master/docs/sql/mysql/mysql-ops.md)
+ - [Redis 运维](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-ops.md)
+- 大数据服务
+ - [Kafka 运维](kafka-install.md)
+ - [Zookeeper 运维](https://github.com/dunwu/javatech/blob/master/docs/technology/monitor/zookeeper-ops.md)
+
+## 🚪 传送门
+
+◾ 💧 [钝悟的 IT 知识图谱](https://dunwu.github.io/waterdrop/) ◾ 🎯 [钝悟的博客](https://dunwu.github.io/blog/) ◾
diff --git a/docs/linux/soft/elastic/README.md b/docs/linux/soft/elastic/README.md
index 6bebd4ed..d3a3e133 100644
--- a/docs/linux/soft/elastic/README.md
+++ b/docs/linux/soft/elastic/README.md
@@ -14,7 +14,7 @@
## 目录
-[Elastic 技术栈之快速指南](elastic-quickstart.md)
+[Elastic 技术栈之入门指南](elastic-quickstart.md)
[Elastic 技术栈之 Logstash 基础](elastic-logstash.md)
diff --git a/docs/linux/soft/elastic/elastic-beats.md b/docs/linux/soft/elastic/elastic-beats.md
index a94b8691..3b33d540 100644
--- a/docs/linux/soft/elastic/elastic-beats.md
+++ b/docs/linux/soft/elastic/elastic-beats.md
@@ -18,7 +18,7 @@ Beats 是安装在服务器上的数据中转代理。
Beats 可以将数据直接传输到 Elasticsearch 或传输到 Logstash 。
-
+
Beats 有多种类型,可以根据实际应用需要选择合适的类型。
@@ -47,7 +47,7 @@ Filebeat带有内部模块(auditd,Apache,Nginx,System和MySQL),可
FileBeat 不会让你的管道超负荷。FileBeat 如果是向 Logstash 传输数据,当 Logstash 忙于处理数据,会通知 FileBeat 放慢读取速度。一旦拥塞得到解决,FileBeat 将恢复到原来的速度并继续传播。
-
+
## 安装
diff --git a/docs/linux/soft/elastic/elastic-kibana.md b/docs/linux/soft/elastic/elastic-kibana.md
index cd85e162..07bcb3ce 100644
--- a/docs/linux/soft/elastic/elastic-kibana.md
+++ b/docs/linux/soft/elastic/elastic-kibana.md
@@ -4,7 +4,7 @@
单击侧面导航栏中的 `Discover` ,可以显示 `Kibana` 的数据查询功能功能。
-
+
在搜索栏中,您可以输入Elasticsearch查询条件来搜索您的数据。您可以在 `Discover` 页面中浏览结果并在 `Visualize` 页面中创建已保存搜索条件的可视化。
@@ -14,7 +14,7 @@
默认情况下,每个匹配文档都显示所有字段。要选择要显示的文档字段,请将鼠标悬停在“可用字段”列表上,然后单击要包含的每个字段旁边的添加按钮。例如,如果只添加account_number,则显示将更改为包含五个帐号的简单列表:
-
+
### 查询语义
@@ -279,7 +279,7 @@ Visualize工具使您能够以多种方式(如饼图、柱状图、曲线图
3. 在 `Field` 列表中选择 `level.keyword`。
4. 点击  按钮来更新图表。
-
+
完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 `Save` 按钮。
@@ -293,7 +293,7 @@ Visualize工具使您能够以多种方式(如饼图、柱状图、曲线图
4. 指定 X 轴所代表的字段
5. 点击  按钮来更新图表。
-
+
完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 `Save` 按钮。
diff --git a/docs/linux/soft/elastic/elastic-logstash.md b/docs/linux/soft/elastic/elastic-logstash.md
index aa93feca..6acf5067 100644
--- a/docs/linux/soft/elastic/elastic-logstash.md
+++ b/docs/linux/soft/elastic/elastic-logstash.md
@@ -32,7 +32,7 @@ Logstash 有两个必要元素:`input` 和 `output` ,一个可选元素:`f
这三个元素,分别代表 Logstash 事件处理的三个阶段:输入 > 过滤器 > 输出。
-
+
- input 负责从数据源采集数据。
- filter 将数据修改为你指定的格式或内容。
diff --git a/docs/linux/soft/elastic/elastic-quickstart.md b/docs/linux/soft/elastic/elastic-quickstart.md
index 31bafd42..25ab374f 100644
--- a/docs/linux/soft/elastic/elastic-quickstart.md
+++ b/docs/linux/soft/elastic/elastic-quickstart.md
@@ -32,7 +32,7 @@ ELK 是 elastic 公司旗下三款产品 [ElasticSearch](https://www.elastic.co/
### Elastic 架构
-
+
> **说明**
>
@@ -274,7 +274,7 @@ output {
大功告成,此后,`io.github.dunwu.spring` 包中的 TRACE 及以上级别的日志信息都会被定向输出到 logstash 服务。
-
+
## 资料
diff --git a/docs/linux/soft/fastdfs.md b/docs/linux/soft/fastdfs.md
index 751c9131..d773b186 100644
--- a/docs/linux/soft/fastdfs.md
+++ b/docs/linux/soft/fastdfs.md
@@ -33,7 +33,7 @@ storage 接受到写文件请求时,会根据配置好的规则(后面会介
**meta data** :文件相关属性,键值对( Key Value Pair) 方式,如:width=1024,heigth=768 。
-
+
diff --git a/docs/linux/soft/gitlab-install.md b/docs/linux/soft/gitlab-ops.md
similarity index 57%
rename from docs/linux/soft/gitlab-install.md
rename to docs/linux/soft/gitlab-ops.md
index 6c8fb058..3d5e564f 100644
--- a/docs/linux/soft/gitlab-install.md
+++ b/docs/linux/soft/gitlab-ops.md
@@ -1,31 +1,14 @@
-# Gitlab 安装
+# Gitlab 运维
-> 环境:
->
-> OS: CentOS7
+## 一、gitlab 安装
-
+### Gitlab 的普通安装
-- [安装 gitlab](#安装-gitlab)
- - [常规安装 gitlab](#常规安装-gitlab)
- - [Docker 安装 gitlab](#docker-安装-gitlab)
-- [安装 gitlab-ci-multi-runner](#安装-gitlab-ci-multi-runner)
- - [常规安装 gitlab-ci-multi-runner](#常规安装-gitlab-ci-multi-runner)
- - [Docker 安装 gitlab-ci-multi-runner](#docker-安装-gitlab-ci-multi-runner)
-- [自签名证书](#自签名证书)
- - [创建证书](#创建证书)
-- [gitlab 配置](#gitlab-配置)
-- [更多内容](#更多内容)
-
-
-
-## 安装 gitlab
-
-### 常规安装 gitlab
+#### 下载
进入官方下载地址:https://about.gitlab.com/install/ ,如下图,选择合适的版本。
-
+
以 CentOS7 为例:
@@ -65,7 +48,7 @@ sudo EXTERNAL_URL="http://gitlab.example.com" yum install -y gitlab-ce
安装完成后,即可通过默认的 root 账户进行登录。更多细节可以参考:[documentation for detailed instructions on installing and configuration](https://docs.gitlab.com/omnibus/README.html#installation-and-configuration-using-omnibus-package)
-### Docker 安装 gitlab
+### Gitlab 的 Docker 安装
拉取镜像
@@ -87,9 +70,63 @@ docker run -d \
gitlab/gitlab-ce
```
-
+
+
+### 自签名证书
+
+首先,创建认证目录
+
+```
+sudo mkdir -p /etc/gitlab/ssl
+sudo chmod 700 /etc/gitlab/ssl
+```
+
+(1)创建 Private Key
+
+```
+sudo openssl genrsa -des3 -out /etc/gitlab/ssl/gitlab.domain.com.key 2048
+```
+
+会提示输入密码,请记住
+
+(2)生成 Certificate Request
+
+```
+sudo openssl req -new -key /etc/gitlab/ssl/gitlab.domain.com.key -out /etc/gitlab/ssl/gitlab.domain.com.csr
+```
+
+根据提示,输入信息
-## 安装 gitlab-ci-multi-runner
+```
+Country Name (2 letter code) [XX]:CN
+State or Province Name (full name) []:JS
+Locality Name (eg, city) [Default City]:NJ
+Organization Name (eg, company) [Default Company Ltd]:xxxxx
+Organizational Unit Name (eg, section) []:
+Common Name (eg, your name or your server's hostname) []:gitlab.xxxx.io
+Email Address []:
+
+Please enter the following 'extra' attributes
+to be sent with your certificate request
+A challenge password []:
+An optional company name []:
+```
+
+(3)移除 Private Key 中的密码短语
+
+```
+sudo cp -v /etc/gitlab/ssl/gitlab.domain.com.{key,original}
+sudo openssl rsa -in /etc/gitlab/ssl/gitlab.domain.com.original -out /etc/gitlab/ssl/gitlab.domain.com.key
+sudo rm -v /etc/gitlab/ssl/gitlab.domain.com.original
+```
+
+(4)设置文件权限
+
+```
+sudo chmod 600 /etc/gitlab/ssl/gitlab.domain.com.*
+```
+
+## 二、gitlab-ci-multi-runner 安装
> 参考:https://docs.gitlab.com/runner/install/
@@ -138,7 +175,7 @@ sudo gitlab-runner register
URL 和令牌信息在 Gitlab 的 Runner 管理页面获取:
-
+
```
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
@@ -193,75 +230,9 @@ docker run -d --name gitlab-runner --restart always \
gitlab/gitlab-runner:latest
```
-## 自签名证书
-
-首先,创建认证目录
-
-```
-sudo mkdir -p /etc/gitlab/ssl
-sudo chmod 700 /etc/gitlab/ssl
-```
-
-### 创建证书
-
-#### 创建 Private Key
-
-```
-sudo openssl genrsa -des3 -out /etc/gitlab/ssl/gitlab.domain.com.key 2048
-```
-
-会提示输入密码,请记住
-
-#### 生成 Certificate Request
-
-```
-sudo openssl req -new -key /etc/gitlab/ssl/gitlab.domain.com.key -out /etc/gitlab/ssl/gitlab.domain.com.csr
-```
-
-根据提示,输入信息
-
-```
-Country Name (2 letter code) [XX]:CN
-State or Province Name (full name) []:JS
-Locality Name (eg, city) [Default City]:NJ
-Organization Name (eg, company) [Default Company Ltd]:xxxxx
-Organizational Unit Name (eg, section) []:
-Common Name (eg, your name or your server's hostname) []:gitlab.xxxx.io
-Email Address []:
-
-Please enter the following 'extra' attributes
-to be sent with your certificate request
-A challenge password []:
-An optional company name []:
-```
-
-#### 移除 Private Key 中的密码短语
-
-```
-sudo cp -v /etc/gitlab/ssl/gitlab.domain.com.{key,original}
-sudo openssl rsa -in /etc/gitlab/ssl/gitlab.domain.com.original -out /etc/gitlab/ssl/gitlab.domain.com.key
-sudo rm -v /etc/gitlab/ssl/gitlab.domain.com.original
-```
-
-#### 创建证书
-
-```
-sudo openssl x509 -req -days 1460 -in /etc/gitlab/ssl/gitlab.domain.com.csr -signkey /etc/gitlab/ssl/gitlab.domain.com.key -out /etc/gitlab/ssl/gitlab.domain.com.crt
-```
+## 三、gitlab 配置
-#### 移除证书请求文件
-
-```
-sudo rm -v /etc/gitlab/ssl/gitlab.domain.com.csr
-```
-
-#### 设置文件权限
-
-```
-sudo chmod 600 /etc/gitlab/ssl/gitlab.domain.com.*
-```
-
-## gitlab 配置
+### 基本配置
```
sudo vim /etc/gitlab/gitlab.rb
@@ -293,7 +264,6 @@ sudo gitlab-ctl reconfigure
sudo gitlab-ctl restart
```
-
### 创建你的 SSH key
1. 使用 Gitlab 的第一步是生成你自己的 SSH 密钥对(Github 也类似)。
@@ -302,31 +272,31 @@ sudo gitlab-ctl restart
3. 打开 **Profile settings**.
-
+
4. 跳转到 **SSH keys** tab 页
-
+
5. 黏贴你的 SSH 公钥内容到 Key 文本框
-
+
6. 为了便于识别,你可以为其命名
-
+
7. 点击 **Add key** 将 SSH 公钥添加到 GitLab
-
+
### 创建项目
-
+
输入项目信息,点击 Create project 按钮,在 Gitlab 创建项目。
-
+
### 克隆项目到本地
@@ -334,31 +304,115 @@ sudo gitlab-ctl restart
拷贝项目地址,然后在本地执行 `git clone `
-
-
### 创建 Issue
依次点击 **Project’s Dashboard** > **Issues** > **New Issue** 可以新建 Issue
-
+
在项目中直接添加 issue
-
+
在未关闭 issue 中,点击 **New Issue** 添加 issue
-
+
通过项目面板添加 issue
-
+
通过 issue 面板添加 issue
-
+
+
+## 四、gitlab 权限配置
+
+### 用户组的权限
+
+- 用户组有这几种权限的概念:`Guest、Reporter、Developer、Master、Owner`
+- 这个概念在设置用户组的时候会遇到,叫做:`Add user(s) to the group`,比如链接:`https:///`
+
+| 行为 | Guest | Reporter | Developer | Master | Owner |
+| ---------- | ----- | -------- | --------- | ------ | ----- |
+| 浏览组 | ✓ | ✓ | ✓ | ✓ | ✓ |
+| 编辑组 | | | | | ✓ |
+| 创建项目 | | | | ✓ | ✓ |
+| 管理组成员 | | | | | ✓ |
+| 移除组 | | | | | |
+
+## 五、备份/迁移/升级
+
+### 备份
+
+#### 手动备份
+
+执行 `gitlab-rake gitlab:backup:create` 开始备份全量数据,成功后,会在 `/var/opt/gitlab/backups` 下生产一个名称类似 `1585910556_2020_04_03_11.3.0_gitlab_backup.tar` 的压缩包。
+
+### 定时自动备份
+
+可以利用 crontab 来定时执行备份命令。
+
+执行 `vim /etc/crontab` 或 `crontab -e` 手动编辑定时任务。
+
+### 迁移
+
+> 迁移前,需要确保新老机器的 Gitlab 版本号一致。
+
+将备份的压缩包拷贝到新机器的备份路径下(默认为 `/var/opt/gitlab/backups`)。
+
+(1)将备份文件权限修改为 777,不然可能恢复的时候会出现权限不够,不能解压的问题
+
+```shell
+chmod 777 1585910556_2020_04_03_11.3.0_gitlab_backup.tar
+```
+
+(2)停止相关数据连接服务
+
+```shell
+gitlab-ctl stop unicorn
+gitlab-ctl stop sidekiq
+```
+
+(3)从备份文件中恢复 Gitlab
+
+```shell
+# gitlab-rake gitlab:backup:restore BACKUP=备份文件编号
+gitlab-rake gitlab:backup:restore BACKUP=1585910556_2020_04_03_11.3.0
+```
+
+### 升级
+
+升级前,一定要做好备份,记录当前 gitlab 的版本号。
+
+第一步还是使用官方命令进行升级。
+
+```shell
+sudo yum install -y gitlab-ce
+```
+
+如果下载速度理想,就无需手动升级安装。不理想就需要`停止自动更新`,并手动下载安装包
+
+访问官方地址,下载对应`版本`,对应`系统`的安装包。
+
+注:可以根据`自动升级时下载的版本`,选择对应文件。
+
+```http
+https://packages.gitlab.com/gitlab/gitlab-ce
+```
+
+安装包手动上传至服务器,并`替换`下载未完成的安装包。下面是升级缓存地址:
+
+```
+/var/cache/yum/x86_64/7/gitlab_gitlab-ce/packages/
+```
+
+再次执行官方升级命令即可完成自动安装。
-## 更多内容
+## 参考资料
-- **引申**
- - [操作系统、运维部署总结系列](https://github.com/dunwu/OS)
+- 官网:https://about.gitlab.com/
+- 中文网:https://www.gitlab.com.cn/
+- 官网下载:https://about.gitlab.com/downloads/
+- 官网安装说明:https://about.gitlab.com/installation/#centos-7
+- [操作系统、运维部署总结系列](https://github.com/dunwu/OS)
diff --git a/docs/linux/soft/jdk-install.md b/docs/linux/soft/jdk-install.md
index bd921cbe..594ec498 100644
--- a/docs/linux/soft/jdk-install.md
+++ b/docs/linux/soft/jdk-install.md
@@ -7,7 +7,7 @@
- [JDK 安装步骤](#jdk-安装步骤)
- [Windows 系统安装方法](#windows-系统安装方法)
- [Linux 系统安装方法](#linux-系统安装方法)
- - [RedHat 发行版本使用 rpm 安装方法](#redhat-发行版本使用-rpm-安装方法)
+ - [RedHat 发行版本使用 rpm 安装方法](#redhat-发行版本使用-rpm-安装方法)
- [参考资料](#参考资料)
@@ -22,13 +22,13 @@ a. 进入 [Java 官网下载页面](https://www.oracle.com/technetwork/java/java
b. 选择需要的版本:
-
+
c. 选择对应操作系统的安装包:
Windows 系统选择 exe 安装包;Mac 系统选择 dmp 安装包;Linux 系统选择 tar.gz 压缩包(RedHat 发行版可以安装 rpm 包)。
-
+
(2)运行安装包,按提示逐步安装
@@ -51,11 +51,11 @@ Windows 系统选择 exe 安装包;Mac 系统选择 dmp 安装包;Linux 系
a. 安装完成后,右击"我的电脑",点击"属性",选择"高级系统设置";
-
+
b. 选择"高级"选项卡,点击"环境变量";
-
+
然后就会出现如下图所示的画面:
@@ -78,7 +78,7 @@ a. "开始"->"运行",键入"cmd";
b. 键入命令: **java -version**、**java**、**javac** 几个命令,出现以下信息,说明环境变量配置成功;
-
+
## Linux 系统安装方法
@@ -97,7 +97,7 @@ $ tar -zxf jdk-8u162-linux-x64.tar.gz
(3)配置系统环境变量
-执行 `/etc/profile` 命令,添加以下内容:
+执行 `vi /etc/profile` 命令,添加以下内容:
```bash
# JDK 的根路径
diff --git a/docs/linux/soft/jenkins-ops.md b/docs/linux/soft/jenkins-ops.md
new file mode 100644
index 00000000..3ed2e485
--- /dev/null
+++ b/docs/linux/soft/jenkins-ops.md
@@ -0,0 +1,362 @@
+# Jenkins 运维
+
+> 环境要求
+>
+> - JDK:JDK7+,官网推荐是 JDK 8
+> - Jenkins:2.190.1
+
+## Jenkins 简介
+
+### Jenkins 是什么
+
+Jenkins 是一款开源 CI&CD 软件,用于自动化各种任务,包括构建、测试和部署软件。
+
+Jenkins 支持各种运行方式,可通过系统包、Docker 或者通过一个独立的 Java 程序。
+
+### CI/CD 是什么
+
+CI(Continuous integration,中文意思是持续集成)是一种软件开发时间。持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。借用网络图片对 CI 加以理解。
+
+
+
+CD(Continuous Delivery, 中文意思持续交付)是在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的 Staging 环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境。下图反应的是 CI/CD 的大概工作模式。
+
+
+
+## Jenkins 安装
+
+> 更详细内容请参考:[Jenkins 官方安装文档](https://jenkins.io/zh/doc/book/installing/)
+
+### War 包部署
+
+安装步骤如下:
+
+(1)下载并解压到本地
+
+进入[官网下载地址](https://jenkins.io/zh/download/),选择合适的版本下载。
+
+我选择的是最新稳定 war 版本 2.89.4:http://mirrors.jenkins.io/war-stable/latest/jenkins.war
+
+我个人喜欢存放在:`/opt/software/jenkins`
+
+```bash
+mkdir -p /opt/software/jenkins
+wget -O /opt/software/jenkins/jenkins.war http://mirrors.jenkins.io/war-stable/latest/jenkins.wa
+```
+
+(2)启动
+
+如果你和我一样,选择 war 版本,那么你可以将 war 移到 Tomcat 的 webapps 目录下,通过 Tomcat 来启动。
+
+当然,也可以通过 `java -jar` 方式来启动。
+
+```bash
+cd /opt/software/jenkins
+nohup java -jar jenkins.war --httpPort=8080 >> nohup.out 2>&1 &
+```
+
+### rpm 包部署
+
+(1)下载安装
+
+```bash
+sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
+sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
+yum install jenkins
+```
+
+(2)启动
+
+```bash
+systemctl start jenkins
+```
+
+### 访问
+
+1. 打开浏览器进入链接 `http://localhost:8080`.
+2. 按照说明完成安装.
+
+## Jenkins 基本使用
+
+Jenkins 是一个强大的 CI 工具,虽然本身使用 Java 开发,但也能用来做其他语言开发的项目 CI。下面讲解如何使用 Jenkins 创建一个构建任务。
+
+登录 Jenkins, 点击左侧的新建,创建新的构建任务。
+
+
+
+跳转到如下界面。任务名称可以自行设定,但需要全局唯一。输入名称后选择构建一个自由风格的软件项目(其他选项不作介绍)。并点击下方的确定按钮即创建了一个构建任务。之后会自动跳转到该 job 的配置页面。
+
+
+
+新建自由风格的软件项目
+
+下图是构建任务设置界面,可以看到上方的几个选项**"General", "源码管理", "构建触发器","构建环境", "构建", "构建后操作"**。下面逐一介绍。
+
+
+
+### General
+
+General 是构建任务的一些基本配置。名称,描述之类的。
+
+
+
+重要配置项:
+
+- **Description**:对构建任务的描述。
+- **Discard old builds**:服务器资源是有限的,有时候保存了太多的历史构建,会导致 Jenkins 速度变慢,并且服务器硬盘资源也会被占满。当然下方的"保持构建天数" 和 保持构建的最大个数是可以自定义的,需要根据实际情况确定一个合理的值。
+
+点击右方的问号图标可以查看帮助信息。
+
+### Source Code Management
+
+**Source Code Management**,即源码管理,就是配置你代码的存放位置。
+
+
+
+- **Git:** 支持主流的 Github 和 Gitlab 代码仓库。因我们的研发团队使用的是 gitlab,所以下面我只会对该项进行介绍。
+- **Repository URL**:仓库地址。
+- **Credentials**:凭证。可以使用 HTTP 方式的用户名密码,也可以是 RSA 文件。 但要通过后面的"ADD"按钮添加凭证。
+- **Branches to build**:构建的分支。`*/master` 表示 master 分支,也可以设置为其他分支。
+- **Repository browser**:你所使用的代码仓库管理工具,如 Github、Gitlab.
+- **Subversion**:即 SVN,这里不作介绍。
+
+### Build Triggers
+
+**Build Triggers**,即构建触发器,用于构建任务的触发器。
+
+
+
+配置说明:
+
+- **Trigger builds remotely (e.g., from scripts)**:触发远程构建(例如,使用脚本)。该选项会提供一个接口,可以用来在代码层面触发构建。
+- **Build after other projects are built**:该选项意思是"在其他项目构建后再构建"。
+- **Build periodically**:周期性的构建。就是每隔一段时间进行构建。日程表类似 linux crontab 书写格式。如:`H/30 * * * *`,表示每隔 30 分钟进行一次构建。
+- **Build when a change is pushed to GitLab:**当有 git push 到 Gitlab 仓库,即触发构建。后面会有一个触发构建的地址,一般被称为 webhooks。需要将这个地址配置到 gitlab 中,webhooks 如何配置后面介绍。这个是常用的构建触发器。
+- **Poll SCM:**该选项是配合上面这个选项使用的。当代码仓库发生改动,jenkins 并不知道。需要配置这个选项,周期性的去检查代码仓库是否发生改动。
+
+### Build Environment
+
+**Build Environment**,即构建环境,配置构建前的一些准备工作,如指定构建工具。
+
+
+
+### Build
+
+Build,即构建。
+
+点击下图中的 Add build step 按钮,会弹出一个构建任务菜单,可以根据实际需要来选择。
+
+
+
+【说明】
+
+- **Copy artifacts from another project**:从其他项目获取构建。一般当本任务有上游任务,需要获取上游任务的构件时使用。比如:有个 Java Web 项目,需要依赖于上一个前端构建任务输出的静态文件压缩包。
+- Eexcute NodeJS script:执行 Nodejs 脚本。默认支持 nodejs、npm 命令。
+- **Eexcute shell**: 执行 shell 脚本。用于 Linux 环境。
+- **Execute Windows batch command**:执行 batch 脚本。用于 Windows 环境。
+- **Invoke Ant**:Ant 是一款 java 项目构建工具。
+- **Invoke Gradle script**:Gradle 构建项目。
+- **Invoke top-level Maven targets**:Maven 构建项目。
+
+### Post-build Actions
+
+**Post-build Actions**,即构建后操作,用于构建完本项目的一些后续操作,比如生成相应的代码测试报告。
+
+
+
+
+
+
+
+个人较常用的配置:
+
+- **Archive the artifacts**:归档构件。
+- **Build other projects**:构建其他项目。
+- **Trigger parameterized build on other projects**:构建其他项目,并传输构建参数。
+- **Publish JUnit test result report**:发布 Junit 测试报告。
+- **E-mail Notification**:邮件通知,构建完成后发邮件到指定的邮箱。
+
+---
+
+**以上配置完成后,点击保存即可。**
+
+### 开始构建
+
+
+
+如上图所示,一切配置好后,即可点击 **Build Now** 开始构建。
+
+### 构建结果
+
+
+
+- **构建状态**
+ - **Successful 蓝色**:构建完成,并且被认为是稳定的。
+ - **Unstable 黄色**:构建完成,但被认为是不稳定的。
+ - **Failed 红色**:构建失败。
+ - **Disable 灰色**:构建已禁用
+- **构建稳定性**
+ - 构建稳定性用天气表示:**晴、晴转多云、多云、小雨、雷阵雨**。天气越好表示构建越稳定,反之亦然。
+- 构建历史界面
+ - **console output**:输出构建的日志信息
+
+## 其他相关配置
+
+### SSH Server 配置
+
+登录 jenkins -> 系统管理 -> 系统设置
+
+配置请看下图:
+
+
+
+重要配置:
+
+- **SSH Servers:** 由于 jenkins 服务器公钥文件我已经配置好,所以之后新增 SSH Servers 只需要配置这一项即可。
+- **Name:** 自定义,需要全局唯一。
+
+- **HostName:** 主机名,直接用 ip 地址即可。
+
+- **Username:** 新增 Server 的用户名,这里配置的是 root。
+
+- **Remote Directory:** 远程目录。jenkins 服务器发送文件给新增的 server 默认是在这个目录。
+
+### 配置 Gitlab webhooks
+
+在 gitlab 的 project 页面 打开**settings**,再打开 **web hooks** 。点击**"ADD WEB HOOK"** 添加 webhook。把之前 jenkins 配置中的那个 url 添加到这里,添加完成后,点击**"TEST HOOK"**进行测试,如果显示 SUCCESS 则表示添加成功。
+
+
+
+
+
+
+
+
+
+
+
+配置 phpunit.xml
+
+phpunit.xml 是 phpunit 这个工具用来单元测试所需要的配置文件。这个文件的名称同样也是可以自定义的,但是要在"build.xml"中配置好名字就行。默认情况下,用"phpunit.xml", 则不需要在"build.xml"中配置文件名。
+
+
+
+build.xml 中 phpunit 配置
+
+fileset dir 指定单元测试文件所在路径,include 指定包含哪些文件,支持通配符匹配。当然也可以用 exclude 关键字指定不包含的文件。
+
+
+
+### jenkins 权限管理
+
+由于 jenkins 默认的权限管理体系不支持用户组或角色的配置,因此需要安装第三发插件来支持角色的配置,本文将使用 Role Strategy Plugin。基于这个插件的权限管理设置请参考这篇文章:[http://blog.csdn.net/russ44/article/details/52276222](https://link.jianshu.com?t=http%3A%2F%2Fblog.csdn.net%2Fruss44%2Farticle%2Fdetails%2F52276222),这里不作详细介绍。
+
+至此,就可以用 jenkins 周而复始的进行 CI 了,当然 jenkins 是一个强大的工具,功能绝不仅仅是以上这些,其他方面要是以后用到,我会更新到这篇文章中。有疑问欢迎在下方留言。
+
+## Jenkins FAQ
+
+### 登录密码
+
+如果不知道初始登录密码,可以通过以下方式查看:
+
+执行命令 `cat /root/.jenkins/secrets/initialAdminPassword`,打印出来的即是初始登录密码。
+
+### 忘记密码
+
+1.执行 `vim /root/.jenkins/config.xml` ,删除以下内容
+
+```xml
+true
+
+ true
+
+
+ true
+ false
+
+```
+
+2.重启 Jenkins 服务;
+
+3.进入首页>“系统管理”>“Configure Global Security”;
+
+4.勾选“启用安全”;
+
+5.点选“Jenkins 专有用户数据库”,并点击“保存”;
+
+6.重新点击首页>“系统管理”,发现此时出现“管理用户”;
+
+7.点击进入展示“用户列表”;
+
+8.点击右侧进入修改密码页面,修改后即可重新登录。
+
+### 卡在 check 页面
+
+**现象**:输入密码后,卡在 check 页面
+
+**原因**:jenkins 在安装插件前总是尝试连接 www.google.com,来判断网络是否连通。谷歌的网站在大陆是连不上的,所以会出现这个问题。
+
+**解决方案**:执行`vim /root/.jenkins/updates/default.json`,将 `connectionCheckUrl` 后的 `www.google.com` 改为 `www.baidu.com` 。然后重启即可。
+
+或者直接执行命令:
+
+```bash
+sed -i 's/www.google.com/www.baidu.com/g' /root/.jenkins/updates/default.json
+```
+
+### 卡在 getting startted 页面
+
+**现象**:卡在 getting startted 页面
+
+**原因**:jenkins 默认的插件下载服务器地址在国外,如果不翻墙下载不了。
+
+**解决方案**:执行`vim /root/.jenkins/hudson.model.UpdateCenter.xml`,将 `` 改为 `http://mirror.xmission.com/jenkins/updates/update-center.json` 。然后重启即可。
+
+或者直接执行命令:
+
+```bash
+sed -i '/^/s/.*/http:\/\/mirror.xmission.com\/jenkins\/updates\/update-center.json<\/url>/g' /root/.jenkins/hudson.model.UpdateCenter.xml
+```
+
+### 以 root 用户运行
+
+(1)修改 jenkins 用户
+
+```bash
+vim /etc/sysconfig/jenkins
+```
+
+修改用户
+
+```bash
+$JENKINS_USER="root"
+```
+
+(2)修改 `Jenkins` 相关文件夹用户权限
+
+```bash
+chown -R root:root /var/lib/jenkins
+chown -R root:root /var/cache/jenkins
+chown -R root:root /var/log/jenkins
+```
+
+(3)重启 Jenkins
+
+```
+systemctl restart jenkins
+```
+
+## 参考资料
+
+- **官方**
+
+ - [Jenkins 官网](https://jenkins.io/zh/)
+ - [Jenkins 中文文档](https://jenkins.io/zh/doc/tutorials/)
+
+- **引申**
+ - [操作系统、运维部署总结系列](https://github.com/dunwu/OS)
+- **文章**
+ - https://jenkins.io/doc/pipeline/tour/getting-started/
+ - https://www.cnblogs.com/austinspark-jessylu/p/6894944.html
+ - http://blog.csdn.net/jlminghui/article/details/54952148
+ - [Jenkins 详细教程](https://www.jianshu.com/p/5f671aca2b5a)
diff --git a/docs/linux/soft/jenkins.md b/docs/linux/soft/jenkins.md
deleted file mode 100644
index de9106da..00000000
--- a/docs/linux/soft/jenkins.md
+++ /dev/null
@@ -1,165 +0,0 @@
-# Jenkins 安装
-
-> 环境要求
->
-> - JDK:JDK7+,官网推荐是 JDK 8
-
-## 部署
-
-> 参考:[官方安装文档](https://jenkins.io/zh/doc/book/installing/)
-
-### War 包部署
-
-安装步骤如下:
-
-(1)下载并解压到本地
-
-进入[官网下载地址](https://jenkins.io/zh/download/),选择合适的版本下载。
-
-我选择的是最新稳定 war 版本 2.89.4:http://mirrors.jenkins.io/war-stable/latest/jenkins.war
-
-我个人喜欢存放在:`/opt/software/jenkins`
-
-```bash
-mkdir -p /opt/software/jenkins
-wget -O /opt/software/jenkins/jenkins.war http://mirrors.jenkins.io/war-stable/latest/jenkins.wa
-```
-
-(2)启动
-
-如果你和我一样,选择 war 版本,那么你可以将 war 移到 Tomcat 的 webapps 目录下,通过 Tomcat 来启动。
-
-当然,也可以通过 `java -jar` 方式来启动。
-
-```bash
-cd /opt/software/jenkins
-nohup java -jar jenkins.war --httpPort=8080 >> nohup.out 2>&1 &
-```
-
-### rpm 包部署
-
-(1)下载安装
-
-```bash
-sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
-sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
-yum install jenkins
-```
-
-(2)启动
-
-```bash
-systemctl start jenkins
-```
-
-### 访问
-
-1. 打开浏览器进入链接 `http://localhost:8080`.
-2. 按照说明完成安装.
-
-## 系统配置
-
-## FAQ
-
-### 登录密码
-
-如果不知道初始登录密码,可以通过以下方式查看:
-
-执行命令 `cat /root/.jenkins/secrets/initialAdminPassword`,打印出来的即是初始登录密码。
-
-### 忘记密码
-
-1.执行 `vim /root/.jenkins/config.xml` ,删除以下内容
-
-```xml
-true
-
- true
-
-
- true
- false
-
-```
-
-2.重启 Jenkins 服务;
-
-3.进入首页>“系统管理”>“Configure Global Security”;
-
-4.勾选“启用安全”;
-
-5.点选“Jenkins 专有用户数据库”,并点击“保存”;
-
-6.重新点击首页>“系统管理”,发现此时出现“管理用户”;
-
-7.点击进入展示“用户列表”;
-
-8.点击右侧进入修改密码页面,修改后即可重新登录。
-
-### 卡在 check 页面
-
-**现象**:输入密码后,卡在 check 页面
-
-**原因**:jenkins 在安装插件前总是尝试连接 www.google.com,来判断网络是否连通。谷歌的网站在大陆是连不上的,所以会出现这个问题。
-
-**解决方案**:执行`vim /root/.jenkins/updates/default.json`,将 `connectionCheckUrl` 后的 `www.google.com` 改为 `www.baidu.com` 。然后重启即可。
-
-或者直接执行命令:
-
-```bash
-sed -i 's/www.google.com/www.baidu.com/g' /root/.jenkins/updates/default.json
-```
-
-### 卡在 getting startted 页面
-
-**现象**:卡在 getting startted 页面
-
-**原因**:jenkins 默认的插件下载服务器地址在国外,如果不翻墙下载不了。
-
-**解决方案**:执行`vim /root/.jenkins/hudson.model.UpdateCenter.xml`,将 `` 改为 `http://mirror.xmission.com/jenkins/updates/update-center.json` 。然后重启即可。
-
-或者直接执行命令:
-
-```bash
-sed -i '/^/s/.*/http:\/\/mirror.xmission.com\/jenkins\/updates\/update-center.json<\/url>/g' /root/.jenkins/hudson.model.UpdateCenter.xml
-```
-
-### 以 root 用户运行
-
-(1)修改 jenkins 用户
-
-```bash
-vim /etc/sysconfig/jenkins
-```
-
-修改用户
-
-```bash
-$JENKINS_USER="root"
-```
-
-(2)修改 `Jenkins` 相关文件夹用户权限
-
-```bash
-chown -R root:root /var/lib/jenkins
-chown -R root:root /var/cache/jenkins
-chown -R root:root /var/log/jenkins
-```
-
-(3)重启 Jenkins
-
-```
-systemctl restart jenkins
-```
-
-## 参考资料
-
-- **官方**
- - [Jenkins 官网](https://jenkins.io/zh/)
-
-- **引申**
- - [操作系统、运维部署总结系列](https://github.com/dunwu/OS)
-- **引用**
- - https://jenkins.io/doc/pipeline/tour/getting-started/
- - https://www.cnblogs.com/austinspark-jessylu/p/6894944.html
- - http://blog.csdn.net/jlminghui/article/details/54952148
diff --git a/docs/linux/soft/maven-install.md b/docs/linux/soft/maven-install.md
index 5b41c115..1ea46d0e 100644
--- a/docs/linux/soft/maven-install.md
+++ b/docs/linux/soft/maven-install.md
@@ -32,7 +32,7 @@
```
# MAVEN 的根路径
export MAVEN_HOME=/opt/maven/apache-maven-3.5.2
-export PATH=\$MAVEN_HOME/bin:\$PATH
+export PATH=$MAVEN_HOME/bin:$PATH
```
执行 `source /etc/profile` ,立即生效
diff --git a/docs/linux/soft/mysql-ops.md b/docs/linux/soft/mysql-ops.md
deleted file mode 100644
index f4548369..00000000
--- a/docs/linux/soft/mysql-ops.md
+++ /dev/null
@@ -1,493 +0,0 @@
-# Mysql 维护
-
-## 安装配置
-
-通过 rpm 包安装
-
-centos 的 yum 源中默认是没有 mysql 的,所以我们需要先去官网下载 mysql 的 repo 源并安装。
-
-### 安装 mysql yum 源
-
-官方下载地址:https://dev.mysql.com/downloads/repo/yum/
-
-(1)下载 yum 源
-
-```bash
-$ wget https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
-```
-
-(2)安装 yum repo 文件并更新 yum 缓存
-
-```bash
-$ rpm -ivh mysql80-community-release-el7-1.noarch.rpm
-```
-
-执行结果:
-
-会在 /etc/yum.repos.d/ 目录下生成两个 repo 文件
-
-```bash
-$ ls | grep mysql
-mysql-community.repo
-mysql-community-source.repo
-```
-
-更新 yum:
-
-```bash
-$ yum clean all
-$ yum makecache
-```
-
-(3)查看 rpm 安装状态
-
-```bash
-$ yum search mysql | grep server
-mysql-community-common.i686 : MySQL database common files for server and client
-mysql-community-common.x86_64 : MySQL database common files for server and
-mysql-community-test.x86_64 : Test suite for the MySQL database server
- : administering MySQL servers
-mysql-community-server.x86_64 : A very fast and reliable SQL database server
-```
-
-通过 yum 安装 mysql 有几个重要目录:
-
-```
-# 数据库目录
-/var/lib/mysql/
-# 配置文件
-/usr/share/mysql(mysql.server命令及配置文件)
-# 相关命令
-/usr/bin(mysqladmin mysqldump等命令)
-# 启动脚本
-/etc/rc.d/init.d/(启动脚本文件mysql的目录)
-# 配置文件
-/etc/my.cnf
-```
-
-### 安装 mysql 服务器
-
-```bash
-$ yum install mysql-community-server
-```
-
-### 启动 mysql 服务
-
-```bash
-# 启动 mysql 服务
-systemctl start mysqld.service
-
-# 查看运行状态
-systemctl status mysqld.service
-
-# 开机启动
-systemctl enable mysqld
-systemctl daemon-reload
-```
-
-### 初始化数据库密码
-
-查看一下初始密码
-
-```bash
-$ grep "password" /var/log/mysqld.log
-2018-09-30T03:13:41.727736Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: %:lt+srWu4k1
-```
-
-执行命令:
-
-```bash
-mysql -uroot -p<临时密码>
-```
-
-输入临时密码,进入 mysql,如果要修改密码,执行以下指令:
-
-```bash
-ALTER user 'root'@'localhost' IDENTIFIED BY '你的密码';
-```
-
-注:密码强度默认为中等,大小写字母、数字、特殊符号,只有修改成功后才能修改配置再设置更简单的密码
-
-### 配置远程访问
-
-```sql
-mysql> CREATE USER 'root'@'%' IDENTIFIED BY '你的密码';
-mysql> GRANT ALL ON *.* TO 'root'@'%';
-mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '你的密码';
-mysql> FLUSH PRIVILEGES;
-```
-
-### 跳过登录认证
-
-```
-vim /etc/my.cnf
-```
-
-在 [mysqld] 下面加上 skip-grant-tables
-
-作用是登录时跳过登录认证,换句话说就是 root 什么密码都可以登录进去。
-
-执行 `service mysqld restart`,重启 mysql
-
-## 部署
-
-### 主从节点部署
-
-假设需要配置一个主从 Mysql 服务器环境
-
-- master 节点:192.168.8.10
-- slave 节点:192.168.8.11
-
-#### 配置主从同步
-
-(1)主节点配置
-
-执行 `vi /etc/my.cnf` ,添加如下配置:
-
-```ini
-[mysqld]
-server-id=1
-log-bin=mysql-bin
-```
-
-- `server-id` - 服务器 ID 号;
-- `log-bin` - 同步的日志路径及文件名,一定注意这个目录要是mysql有权限写入的;
-
-(2)从节点配置
-
-执行 `vi /etc/my.cnf` ,添加如下配置:
-
-```ini
-[mysqld]
-server-id=2
-log-bin=mysql-bin
-```
-
-(3)创建用于复制操作的用户
-
-```sql
-mysql> CREATE USER 'sync'@'192.168.8.11' IDENTIFIED WITH mysql_native_password BY '密码'; -- 创建用户
-mysql> GRANT REPLICATION SLAVE ON *.* TO 'sync'@'192.168.8.11'; -- 授权
-mysql> FLUSH PRIVILEGES; -- 刷新授权表信息
-```
-
-(4)查看主节点状态
-
-```sql
-mysql> show master status;
-+------------------+----------+--------------+---------------------------------------------+-------------------+
-| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
-+------------------+----------+--------------+---------------------------------------------+-------------------+
-| mysql-bin.000001 | 4202 | | mysql,information_schema,performance_schema | |
-+------------------+----------+--------------+---------------------------------------------+-------------------+
-1 row in set (0.00 sec)
-```
-
-(5)在Slave节点上设置主节点参数
-
-`MASTER_LOG_FILE` 和 `MASTER_LOG_POS` 参数要分别与 `show master status` 指令获得的 `File` 和 `Position` 属性值对应。
-
-```sql
-mysql> CHANGE MASTER TO
-MASTER_HOST='192.168.199.149',
-MASTER_USER='sync',
-MASTER_PASSWORD='密码',
-MASTER_LOG_FILE='binlog.000001',
-MASTER_LOG_POS=4202;
-
-```
-
-(6)查看主从同步状态
-
-```
-mysql> show slave status\G;
-```
-
-说明:如果以下两项参数均为 YES,说明配置正确。
-
-- `Slave_IO_Running`
-- `Slave_SQL_Running`
-
-(7)启动 slave 进程
-
-```
-mysql> start slave;
-```
-
-#### 同步主节点已有数据到从节点
-
-主库操作:
-
-(1)停止主库的数据更新操作
-
-```sql
-mysql> flush tables with read lock;
-```
-
-(2)新开终端,生成主数据库的备份(导出数据库)
-
-```bash
-$ mysqldump -uroot -p<密码> test > test.sql
-```
-
-(3)将备份文件传到从库
-
-```bash
-$ scp test.sql root@192.168.8.11:/root/
-```
-
-(4)主库解锁
-
-```mysql
-mysql> unlock tables;
-```
-
- 从库操作:
-
-(1)停止从库slave
-
-```mysql
-mysql> stop slave;
-```
-
-(2)新建数据库test
-
-```mysql
-mysql> create database test default charset utf8;
-```
-
-(3)导入数据
-
-```bash
-$ mysql -uroot -ptest123 cmdb show databases;
-+--------------------+
-| Database |
-+--------------------+
-| information_schema |
-| cmdb |
-| mysql |
-| performance_schema |
-| test |
-+--------------------+
-```
-
-## 运维
-
-### 创建用户
-
-```
-CREATE USER 'username'@'host' IDENTIFIED BY 'password';
-```
-
-说明:
-
-- username:你将创建的用户名
-- host:指定该用户在哪个主机上可以登陆,如果是本地用户可用 localhost,如果想让该用户可以**从任意远程主机登陆**,可以使用通配符`%`
-- password:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器
-
-示例:
-
-```sql
-CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456';
-CREATE USER 'pig'@'192.168.1.101_' IDENDIFIED BY '123456';
-CREATE USER 'pig'@'%' IDENTIFIED BY '123456';
-CREATE USER 'pig'@'%' IDENTIFIED BY '';
-CREATE USER 'pig'@'%';
-```
-
-### 授权
-
-命令:
-
-```sql
-GRANT privileges ON databasename.tablename TO 'username'@'host'
-```
-
-说明:
-
-- privileges:用户的操作权限,如`SELECT`,`INSERT`,`UPDATE`等,如果要授予所的权限则使用`ALL`
-- databasename:数据库名
-- tablename:表名,如果要授予该用户对所有数据库和表的相应操作权限则可用`*`表示,如`*.*`
-
-示例:
-
-```sql
-GRANT SELECT, INSERT ON test.user TO 'pig'@'%';
-GRANT ALL ON *.* TO 'pig'@'%';
-GRANT ALL ON maindataplus.* TO 'pig'@'%';
-```
-
-注意:
-
-用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令:
-
-```sql
-GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;
-```
-
-### 撤销授权
-
-命令:
-
-```
-REVOKE privilege ON databasename.tablename FROM 'username'@'host';
-```
-
-说明:
-
-privilege, databasename, tablename:同授权部分
-
-例子:
-
-```
-REVOKE SELECT ON *.* FROM 'pig'@'%';
-```
-
-注意:
-
-假如你在给用户`'pig'@'%'`授权的时候是这样的(或类似的):`GRANT SELECT ON test.user TO 'pig'@'%'`,则在使用`REVOKE SELECT ON *.* FROM 'pig'@'%';`命令并不能撤销该用户对 test 数据库中 user 表的`SELECT` 操作。相反,如果授权使用的是`GRANT SELECT ON *.* TO 'pig'@'%';`则`REVOKE SELECT ON test.user FROM 'pig'@'%';`命令也不能撤销该用户对 test 数据库中 user 表的`Select`权限。
-
-具体信息可以用命令`SHOW GRANTS FOR 'pig'@'%';` 查看。
-
-### 更改用户密码
-
-```sql
-SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');
-```
-
-如果是当前登陆用户用:
-
-```sql
-SET PASSWORD = PASSWORD("newpassword");
-```
-
-示例:
-
-```sql
-SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456");
-```
-
-### 备份与恢复
-
-Mysql 备份数据使用 mysqldump 命令。
-
-mysqldump 将数据库中的数据备份成一个文本文件,表的结构和表中的数据将存储在生成的文本文件中。
-
-备份:
-
-(1)备份一个数据库
-
-语法:
-
-```
-mysqldump -u -p [ ...] > backup.sql
-```
-
-- username 数据库用户
-- dbname 数据库名称
-- table1 和 table2 参数表示需要备份的表的名称,为空则整个数据库备份;
-- BackupName.sql 参数表设计备份文件的名称,文件名前面可以加上一个绝对路径。通常将数据库被分成一个后缀名为 sql 的文件
-
-(2)备份多个数据库
-
-```
-mysqldump -u -p --databases ... > backup.sql
-```
-
-(3)备份所有数据库
-
-```
-mysqldump -u -p -all-databases > backup.sql
-```
-
-恢复:
-
-Mysql 恢复数据使用 mysqldump 命令。
-
-语法:
-
-```
-mysql -u -p < backup.sql
-```
-
-### 卸载
-
-(1)查看已安装的 mysql
-
-```bash
-$ rpm -qa | grep -i mysql
-perl-DBD-MySQL-4.023-6.el7.x86_64
-mysql80-community-release-el7-1.noarch
-mysql-community-common-8.0.12-1.el7.x86_64
-mysql-community-client-8.0.12-1.el7.x86_64
-mysql-community-libs-compat-8.0.12-1.el7.x86_64
-mysql-community-libs-8.0.12-1.el7.x86_64
-```
-
-(2)卸载 mysql
-
-```bash
-$ yum remove mysql-community-server.x86_64
-```
-
-## 问题
-
-### JDBC 与 Mysql 因 CST 时区协商无解导致偏差了 14 或 13 小时
-
-**现象**
-
-数据库中存储的 Timestamp 字段值比真实值少了 13 个小时。
-
-**原因**
-
-- 当 JDBC 与 MySQL 开始建立连接时,会获取服务器参数。
-- 当 MySQL 的 `time_zone` 值为 `SYSTEM` 时,会取 `system_time_zone` 值作为协调时区,若得到的是 `CST` 那么 Java 会误以为这是 `CST -0500` ,因此会给出错误的时区信息(国内一般是`CST +0800`,即东八区)。
-
-> 查看时区方法:
->
-> 通过 `show variables like '%time_zone%';` 命令查看 Mysql 时区配置:
->
-> ```
-> mysql> show variables like '%time_zone%';
-> +------------------+--------+
-> | Variable_name | Value |
-> +------------------+--------+
-> | system_time_zone | CST |
-> | time_zone | SYSTEM |
-> +------------------+--------+
-> ```
-
-**解决方案**
-
-方案一
-
-```
-mysql> set global time_zone = '+08:00';
-Query OK, 0 rows affected (0.00 sec)
-
-mysql> set time_zone = '+08:00';
-Query OK, 0 rows affected (0.00 sec)
-```
-
-方案二
-
-修改 `my.cnf` 文件,在 `[mysqld]` 节下增加 `default-time-zone = '+08:00'` ,然后重启。
-
-## 参考资料
-
-- https://www.cnblogs.com/xiaopotian/p/8196464.html
-- https://www.cnblogs.com/bigbrotherer/p/7241845.html
-- https://blog.csdn.net/managementandjava/article/details/80039650
-- http://www.manongjc.com/article/6996.html
-- https://www.cnblogs.com/xyabk/p/8967990.html
-- [MySQL 8.0主从(Master-Slave)配置](https://blog.csdn.net/zyhlwzy/article/details/80569422)
-
-## :door: 传送门
-
-| [技术文档归档](https://github.com/dunwu/blog) | [数据库教程系列](https://github.com/dunwu/db-tutorial/codes) |
diff --git a/docs/linux/soft/nexus-install.md b/docs/linux/soft/nexus-install.md
deleted file mode 100644
index 5f5337ca..00000000
--- a/docs/linux/soft/nexus-install.md
+++ /dev/null
@@ -1,193 +0,0 @@
-# 部署并使用 Nexus 作为 Maven 私服
-
-> 关键词:maven, nexus
->
-> 部署环境
->
-> - Nexus 3.13.0
-> - JDK 1.8
-> - Maven 3.5.4
-
-
-
-- [下载安装 Nexus](#下载安装-nexus)
-- [启动停止 Nexus](#启动停止-nexus)
-- [使用 Nexus](#使用-nexus)
- - [配置 settings.xml](#配置-settingsxml)
- - [配置 pom.xml](#配置-pomxml)
- - [执行 maven 构建](#执行-maven-构建)
-- [参考资料](#参考资料)
-
-
-
-## 下载安装 Nexus
-
-进入[官方下载地址](https://www.sonatype.com/download-oss-sonatype),选择合适版本下载。
-
-
-
-本人希望将 Nexus 部署在 Linux 机器,所以选用的是 Unix 版本。
-
-这里,如果想通过命令方式直接下载(比如用脚本安装),可以在[官方历史发布版本页面](https://help.sonatype.com/repomanager3/download/download-archives---repository-manager-3)中找到合适版本,然后执行以下命令:
-
-```sh
-wget -O /opt/maven/nexus-unix.tar.gz http://download.sonatype.com/nexus/3/nexus-3.13.0-01-unix.tar.gz
-tar -zxf nexus-unix.tar.gz
-```
-
-解压后,有两个目录:
-
-- nexus-3.13.0-01 - 包含了 Nexus 运行所需要的文件。是 Nexus 运行必须的。
-- sonatype-work - 包含了 Nexus 生成的配置文件、日志文件、仓库文件等。当我们需要备份 Nexus 的时候默认备份此目录即可。
-
-## 启动停止 Nexus
-
-进入 nexus-3.13.0-01/bin 目录,有一个可执行脚本 nexus。
-
-执行 `./nexus`,可以查看允许执行的参数,如下所示,含义可谓一目了然:
-
-```sh
-$ ./nexus
-Usage: ./nexus {start|stop|run|run-redirect|status|restart|force-reload}
-```
-
-- 启动 nexus - `./nexus start`
-- 停止 nexus -
-
-启动成功后,在浏览器中访问 `http://:8081`,欢迎页面如下图所示:
-
-
-
-点击右上角 Sign in 登录,默认用户名/密码为:admin/admin123。
-
-有必要提一下的是,在 Nexus 的 Repositories 管理页面,展示了可用的 maven 仓库,如下图所示:
-
-
-
-> 说明:
->
-> - maven-central - maven 中央库(如果没有配置 mirror,默认就从这里下载 jar 包),从 https://repo1.maven.org/maven2/ 获取资源
-> - maven-releases - 存储私有仓库的发行版 jar 包
-> - maven-snapshots - 存储私有仓库的快照版(调试版本) jar 包
-> - maven-public - 私有仓库的公共空间,把上面三个仓库组合在一起对外提供服务,在本地 maven 基础配置 settings.xml 中使用。
-
-## 使用 Nexus
-
-如果要使用 Nexus,还必须在 settings.xml 和 pom.xml 中配置认证信息。
-
-### 配置 settings.xml
-
-一份完整的 `settings.xml`:
-
-```xml
-
-
-
-
- org.sonatype.plugins
-
-
-
-
-
- releases
- admin
- admin123
-
-
- snapshots
- admin
- admin123
-
-
-
-
-
-
- public
- *
- http://10.255.255.224:8081/repository/maven-public/
-
-
-
-
-
- zp
-
-
- central
- http://central
-
- true
-
-
- true
-
-
-
-
-
- central
- http://central
-
- true
-
-
- true
- always
-
-
-
-
-
-
-
- zp
-
-
-```
-
-### 配置 pom.xml
-
-在 pom.xml 中添加如下配置:
-
-```xml
-
-
- releases
- Releases
- http://10.255.255.224:8081/repository/maven-releases
-
-
- snapshots
- Snapshot
- http://10.255.255.224:8081/repository/maven-snapshots
-
-
-```
-
-> 注意:
->
-> - `` 和 `` 的 id 必须和 `settings.xml` 配置文件中的 `` 标签中的 id 匹配。
-> - `` 标签的地址需要和 maven 私服的地址匹配。
-
-### 执行 maven 构建
-
-如果要使用 settings.xml 中的私服配置,必须通过指定 `-P zp` 来激活 profile。
-
-示例:
-
-```sh
-# 编译并打包 maven 项目
-$ mvn clean package -Dmaven.skip.test=true -P zp
-
-# 编译并上传 maven 交付件(jar 包)
-$ mvn clean deploy -Dmaven.skip.test=true -P zp
-```
-
-## 参考资料
-
-- https://www.cnblogs.com/hoobey/p/6102382.html
-- https://blog.csdn.net/wzygis/article/details/49276779
-- https://blog.csdn.net/clj198606061111/article/details/52200928
diff --git a/docs/linux/soft/nexus-ops.md b/docs/linux/soft/nexus-ops.md
new file mode 100644
index 00000000..c68af2ab
--- /dev/null
+++ b/docs/linux/soft/nexus-ops.md
@@ -0,0 +1,345 @@
+# Nexus 运维
+
+> Nexus 是一个强大的 Maven 仓库管理器,可以用来搭建 Maven 私服。
+>
+> 关键词:maven, nexus
+>
+> 部署环境:
+>
+> - Nexus 3.13.0
+> - JDK 1.8
+> - Maven 3.5.4
+
+## 一、Nexus 安装
+
+进入[官方下载地址](https://www.sonatype.com/download-oss-sonatype),选择合适版本下载。
+
+
+
+本人将 Nexus 部署在 Linux 机器,所以选用的是 Unix 版本。
+
+这里,如果想通过命令方式直接下载(比如用脚本安装),可以在[官方历史发布版本页面](https://help.sonatype.com/repomanager3/download/download-archives---repository-manager-3)中找到合适版本,然后执行以下命令:
+
+```shell
+# 个人习惯将 nexus 安装在 /opt/maven 目录下
+wget -O /opt/maven/nexus-unix.tar.gz http://download.sonatype.com/nexus/3/nexus-3.13.0-01-unix.tar.gz
+
+```
+
+- 【解压】执行 `tar -zxf nexus-unix.tar.gz` 命令,会解压出两个目录:
+ - `nexus-` - 程序目录。包含了 Nexus 运行所需要的文件。是 Nexus 运行必须的。
+ - `nexus-/etc` - 配置目录。
+ - `nexus-/etc/nexus.properties` - nexus 核心配置文件(默认 etc 目录下有 `nexus-default.properties`,可以基于此修改)。
+ - `sonatype-work` - 仓库目录。包含了 Nexus 生成的配置文件、日志文件、仓库文件等。当我们需要备份 Nexus 的时候默认备份此目录即可。
+- [修改环境变量】执行 `vim /etc/profile`,在文件尾部添加以下内容:
+
+```
+NEXUS_HOME=/usr/program/nexus2.11.4
+export NEXUS_HOME
+```
+
+刷新环境变量:`source /etc/profile`
+
+- 【检查安装是否成功】执行 `nexus -version` 查看是否安装成功。
+- 【防火墙】
+ - iptabes
+ - 添加规则:`iptables -I INPUT -p tcp -m tcp --dport 8081 -j ACCEPT`
+ - 载入规则:`/etc/rc.d/init.d/iptables save`
+ - 重启 iptables:`service iptables restart`
+ - firewalld
+ - 添加规则:`firewall-cmd --zone=public --add-port=8081/tcp --permanent`
+ - 载入规则:`firewall-cmd --reload`
+
+## 二、Nexus 使用
+
+### 启动/停止 Nexus
+
+进入 `nexus-3.13.0-01/bin` 目录,有一个可执行脚本 nexus。
+
+执行 `./nexus`,可以查看允许执行的参数,如下所示,含义可谓一目了然:
+
+```shell
+$ ./nexus
+Usage: ./nexus {start|stop|run|run-redirect|status|restart|force-reload}
+```
+
+- 启动 nexus - `./nexus start`
+- 停止 nexus - `./nexus stop`
+- 重启 nexus - `./nexus restart`
+
+Nexus 的默认启动端口为 `8081`,启动成功后,在浏览器中访问 `http://:8081`,欢迎页面如下图所示:
+
+
+
+点击右上角 Sign in 登录,默认用户名/密码为:`admin/admin123`。
+
+### 配置 maven 仓库
+
+Nexus 中的仓库有以下类型:
+
+- `hosted` - 宿主仓库。主要用于部署无法从公共仓库获取的构件(如 oracle 的 JDBC 驱动)以及自己或第三方的项目构件;
+- `proxy` - 代理仓库。代理公共的远程仓库;
+- `virtual` - 虚拟仓库。用于适配 Maven 1;
+- `group` - 仓库组。Nexus 通过仓库组的概念统一管理多个仓库,这样我们在项目中直接请求仓库组即可请求到仓库组管理的多个仓库。
+
+
+
+建议配置如下:
+
+- **hosted 仓库**
+ - **maven-releases** - 存储私有仓库的发行版 jar 包
+ - **maven-snapshots** - 存储私有仓库的快照版(调试版本) jar 包
+- **proxy 仓库**
+ - **maven-central-maven** - 中央库(如果没有配置 mirror,默认就从这里下载 jar 包),从 https://repo1.maven.org/maven2/ 获取资源
+ - **maven-aliyun** - 国内 maven 仓库,提高访问速度。
+- **group 仓库**
+ - **maven-public** - 私有仓库的公共空间,把上面三个仓库组合在一起对外提供服务,在本地 maven 基础配置 settings.xml 中使用。
+
+
+
+> 其中:
+>
+> **maven-central**、**maven-public**、**maven-release**、**maven-snapshot** 仓库是默认配置好的 maven 仓库。maven-central 配置的是 `https://repo1.maven.org/maven2/` 的代理仓库,即 maven 中央仓库地址。
+
+参考配置如下:
+
+
+
+推荐配置的代理仓库:
+
+- OSS SNAPSHOT 仓库:`http://oss.jfrog.org/artifactory/oss-snapshot-local/`
+- aliyun 仓库(受限于国内网络,可以通过它来加速):`http://maven.aliyun.com/nexus/content/groups/public/`
+
+### 配置 yum 仓库
+
+
+
+推荐配置的 yum 代理仓库:
+
+- aliyun yum 仓库:`http://mirrors.aliyun.com/centos`
+
+配置本地 yum:
+
+(1)新增 nexus.repo 文件,内容如下:
+
+```ini
+[base]
+name=Nexus
+baseurl= http://:/repository/yum-aliyun/$releasever/os/$basearch/
+enabled=1
+gpgcheck=0
+priority=1
+```
+
+(2)更新 yum 缓存,执行以下命令:
+
+```shell
+yum clean all
+yum makecache
+```
+
+### 定时任务
+
+随着 jar 包越来越多,尤其是 SNAPSHOT 包由于不限制重复上传,尤其容易导致磁盘空间膨胀。所以,需要定期进行清理或修复。
+
+Nexus 内置了多个定时任务,可以执行清理。
+
+【示例】定期清理 SNAPSHOST
+
+
+
+## 三、开机自启动
+
+作为常用服务,有必要将 Nexus 设为 `systemd` 服务,以便在断电恢复后自动重启。
+
+配置方法如下:
+
+在 `/lib/systemd/system` 目录下创建 `nexus.service` 文件,内容如下:
+
+```ini
+[Unit]
+Description=nexus
+After=network.target
+
+[Service]
+Type=forking
+LimitNOFILE=65536 #警告处理
+Environment=RUN_AS_USER=root
+ExecStart=/opt/maven/nexus-3.13.0-01/bin/nexus start
+ExecReload=/opt/maven/nexus-3.13.0-01/bin/nexus restart
+ExecStop=/opt/maven/nexus-3.13.0-01/bin/nexus stop
+Restart=on-failure
+PrivateTmp=true
+
+[Install]
+WantedBy=multi-user.target
+```
+
+保存后,可以使用以下命令应用 nexus 服务:
+
+- `systemctl enable nexus` - 启动 nexus 开机启动
+- `systemctl disable nexus` - 关闭 nexus 开机启动
+- `systemctl start nexus` - 启动 nexus 服务
+- `systemctl stop nexus` - 停止 nexus 服务
+- `systemctl restart nexus` - 重启 nexus 服务
+
+> 执行 `systemctl enable nexus` 后,再执行 reboot 重启,重连后,可以检测是否成功开机自动重启。
+
+## 四、Nexus 和 Maven
+
+Nexus 是 maven 私服。现在,Nexus 服务器已经部署好了,如何配合 maven 使用呢?
+
+### 配置 settings.xml
+
+如果要使用 Nexus,还必须在 `settings.xml` 和 `pom.xml` 中配置认证信息。
+
+一份完整的 `settings.xml`:
+
+```xml
+
+
+
+
+ org.sonatype.plugins
+
+
+
+ D:\Tools\maven\.m2
+
+
+
+
+ releases
+ admin
+ admin123
+
+
+ snapshots
+ admin
+ admin123
+
+
+
+
+
+
+ public
+ *
+
+ http://10.255.255.224:8081/repository/maven-public/
+
+
+
+
+
+ zp
+
+
+ central
+ http://central
+
+ true
+
+
+ true
+
+
+
+
+
+ central
+ http://central
+
+ true
+
+
+ true
+ always
+
+
+
+
+
+
+
+ zp
+
+
+```
+
+### 配置 pom.xml
+
+在 `pom.xml` 中添加如下配置,这样就可以执行 `mvn deploy`,将本地构建的 jar、war 等包发布到私服上。
+
+```xml
+
+
+ releases
+ Releases
+ http://10.255.255.224:8081/repository/maven-releases
+
+
+ snapshots
+ Snapshot
+ http://10.255.255.224:8081/repository/maven-snapshots
+
+
+```
+
+> 🔔 注意:
+>
+> - `` 和 `` 的 id 必须和 `settings.xml` 配置文件中的 `` 标签中的 id 匹配。
+> - `` 标签的地址需要和 maven 私服的地址匹配。
+
+### 执行 maven 构建
+
+如果要使用 `settings.xml` 中的私服配置,必须通过指定 `-P zp` 来激活 profile。
+
+示例:
+
+```shell
+# 编译并打包 maven 项目
+$ mvn clean package -Dmaven.skip.test=true -P zp
+
+# 编译并上传 maven 交付件(jar 包)
+$ mvn clean deploy -Dmaven.skip.test=true -P zp
+```
+
+> 至此,已经可以正常向 Nexus 上传、下载 jar 包。
+
+## 五、备份和迁移
+
+Nexus 三个重要目录:
+
+| 名称 | 目录名 | 重要配置文件 |
+| :----------------- | :------------- | :------------------------------------------------ |
+| nexus 主目录 | nexus-2.6.4-02 | conf/nexus.properties 里面有 sonatype-work 的地址 |
+| sonatype-work 目录 | sonatype-work | nexus/conf/nexus.xml 里面有 storage 的地址 |
+| storage 目录 | storage | 里面主要是各种程序的 jar 包等 |
+
+### 备份
+
+Nexus 的数据都存储在 sonatype-work 目录,备份 Nexus 数据只需要将其打包即可。
+
+### 迁移
+
+将原 Nexus 服务器中的 sonatype-work 目录迁移到新 Nexus 服务器的 sonatype-work 目录下。
+
+## 六、FAQ
+
+### 配置 INSTALL4J_JAVA_HOME
+
+我在工作中遇到 nexus systemctl 服务无法自启动的问题,通过查看状态,发现以下报错:
+
+```
+Please define INSTALL4J_JAVA_HOME to point to a suitable JVM
+```
+
+通过排查,找到原因:即使环境上已安装 JDK,且配置了 JAVA_HOME,但 nexus 仍然无法正确找到 JDK,需要在 `/bin/nexus` 中指定 `INSTALL4J_JAVA_HOME_OVERRIDE=`
+
+## 参考资料
+
+- [maven 私库 nexus3 安装及使用](https://blog.csdn.net/clj198606061111/article/details/52200928)
+- [Nexus 安装 使用说明](https://www.cnblogs.com/jtlgb/p/7473837.html)
+- [企业级开源仓库 nexus3 实战应用–使用 nexus3 配置 yum 私有仓库](http://www.eryajf.net/2002.html)
diff --git a/docs/linux/soft/redis-ops.md b/docs/linux/soft/redis-ops.md
deleted file mode 100644
index 77dcb8b5..00000000
--- a/docs/linux/soft/redis-ops.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# Redis 安装
-
-
-
-- [安装](#安装)
-- [启动](#启动)
-- [脚本](#脚本)
-
-
-
-## 安装
-
-安装步骤如下:
-
-(1)下载并解压到本地
-
-进入官网下载地址:https://redis.io/download ,选择合适的版本下载。
-
-我选择的是最新稳定版本 4.0.8:http://download.redis.io/releases/redis-4.0.8.tar.gz
-
-我个人喜欢存放在:`/opt/redis`
-
-```
-wget -O /opt/redis/redis-4.0.8.tar.gz http://download.redis.io/releases/redis-4.0.8.tar.gz
-cd /opt/redis
-tar zxvf redis-4.0.8.tar.gz
-```
-
-(2)编译安装
-
-执行以下命令:
-
-```
-cd /opt/redis/redis-4.0.8
-make
-```
-
-## 启动
-
-**启动 redis 服务**
-
-```
-cd /opt/redis/redis-4.0.8/src
-./redis-server
-```
-
-**启动 redis 客户端**
-
-```
-cd /opt/redis/redis-4.0.8/src
-./redis-cli
-```
-
-## 脚本
-
-以上两种安装方式,我都写了脚本去执行:
-
-| [安装脚本](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft) |
diff --git a/docs/linux/soft/svn-ops.md b/docs/linux/soft/svn-ops.md
index fd83dbcb..3e27a4b5 100644
--- a/docs/linux/soft/svn-ops.md
+++ b/docs/linux/soft/svn-ops.md
@@ -4,30 +4,15 @@
>
> 本文目的在于记录 svn 的安装、配置、使用。
-
+## 安装
-- [1. 安装配置](#1-安装配置)
- - [1.1. 安装 svn](#11-安装-svn)
- - [1.2. 创建 svn 仓库](#12-创建-svn-仓库)
- - [1.3. 配置 svnserve.conf](#13-配置-svnserveconf)
- - [1.4. 配置 passwd](#14-配置-passwd)
- - [1.5. 配置 authz](#15-配置-authz)
- - [1.6. 启动关闭 svn](#16-启动关闭-svn)
- - [1.7. 开机自启动 svn 方法](#17-开机自启动-svn-方法)
- - [1.8. svn 客户端访问](#18-svn-客户端访问)
-- [2. 参考资料](#2-参考资料)
-
-
-
-## 1. 安装配置
-
-### 1.1. 安装 svn
+### 安装 svn
```bash
$ yum install -y subversion
```
-### 1.2. 创建 svn 仓库
+### 创建 svn 仓库
```bash
$ mkdir -p /share/svn
@@ -38,11 +23,13 @@ conf db format hooks locks README.txt
在 conf 目录下有三个重要的配置文件
-- authz - 是权限控制文件
-- passwd - 是帐号密码文件
-- svnserve.conf - 是 SVN 服务配置文件
+- `authz` - 是权限控制文件
+- `passwd` - 是帐号密码文件
+- `svnserve.conf` - 是 SVN 服务配置文件
-### 1.3. 配置 svnserve.conf
+## 配置
+
+### 配置 svnserve.conf
```bash
$ vim /share/svn/conf/svnserve.conf
@@ -58,13 +45,13 @@ authz-db = authz #使用哪个文件作为权限文件
realm = /share/svn # 认证空间名,版本库所在目录
```
-### 1.4. 配置 passwd
+### 配置 passwd
```bash
$ vim /share/svn/conf/passwd
```
-添加内容如下:
+添加新用户的用户名/密码如下:
```ini
[users]
@@ -73,13 +60,13 @@ user2 = 123456
user3 = 123456
```
-### 1.5. 配置 authz
+### 配置 authz
```bash
$ vim /share/svn/conf/authz
```
-添加内容如下:
+指定用户的访问权限(`r` 为读权限;`w` 为写权限):
```ini
[/]
@@ -89,14 +76,16 @@ user3 = rw
*=
```
-### 1.6. 启动关闭 svn
+## 服务器管理
+
+### 启动关闭 svn
```bash
$ svnserve -d -r /share/svn # 启动 svn
$ killall svnserve # 关闭 svn
```
-### 1.7. 开机自启动 svn 方法
+### 开机自启动 svn 方法
安装好 svn 服务后,默认是没有随系统启动自动启动的,而一般我们有要求 svn 服务稳定持续的提供服务。所以,有必要配置开机自启动 svn 服务。
@@ -137,7 +126,14 @@ $ vi /etc/sysconfig/svnserve
重启服务器后,执行 `ps -ef | grep svn` 应该可以看到 svn 服务的进程已经启动。
-### 1.8. svn 客户端访问
+- 启动一个服务 - systemctl start svnserve.service
+- 关闭一个服务 - systemctl stop svnserve.service
+- 重启一个服务 - systemctl restart svnserve.service
+- 显示一个服务的状态 - systemctl status svnserve.service
+- 在开机时启用一个服务 - systemctl enable svnserve.service
+- 在开机时禁用一个服务 - systemctl disable svnserve.service
+
+## 客户端使用
进入 [svn 官方下载地址](https://tortoisesvn.net/downloads.html),选择合适的版本,下载并安装。
@@ -145,9 +141,9 @@ $ vi /etc/sysconfig/svnserve
在新的窗口,输入地址 `svn://<你的 IP>` 即可,不出意外输入用户名和密码就能连接成功了(这里的用户、密码必须在 passwd 配置文件的清单中)。默认端口 3690,如果你修改了端口,那么要记得加上端口号。如下图所示:
-
+
-## 2. 参考资料
+## 参考资料
- https://www.cnblogs.com/liuxianan/p/linux_install_svn_server.html
- https://blog.csdn.net/testcs_dn/article/details/45395645
diff --git a/docs/linux/soft/yapi-ops.md b/docs/linux/soft/yapi-ops.md
index 4276c0e7..938cf73f 100644
--- a/docs/linux/soft/yapi-ops.md
+++ b/docs/linux/soft/yapi-ops.md
@@ -4,17 +4,17 @@
>
> 本文目的在于记录 svn 的安装、配置、使用。
-
+
- [1. 普通部署](#1-普通部署)
- - [1.1. 环境要求](#11-环境要求)
- - [1.2. 部署](#12-部署)
- - [1.3. 升级](#13-升级)
+ - [1.1. 环境要求](#11-环境要求)
+ - [1.2. 部署](#12-部署)
+ - [1.3. 升级](#13-升级)
- [2. Docker 部署](#2-docker-部署)
- - [2.1. 环境要求](#21-环境要求)
- - [2.2. 部署](#22-部署)
+ - [2.1. 环境要求](#21-环境要求)
+ - [2.2. 部署](#22-部署)
- [3. 参考资料](#3-参考资料)
diff --git a/docs/linux/soft/zookeeper-install.md b/docs/linux/soft/zookeeper-install.md
deleted file mode 100644
index ffb12795..00000000
--- a/docs/linux/soft/zookeeper-install.md
+++ /dev/null
@@ -1,96 +0,0 @@
-# ZooKeeper 安装部署
-
-> 环境要求:JDK6+
-
-
-
-- [下载解压 ZooKeeper](#下载解压-zookeeper)
-- [创建配置文件](#创建配置文件)
-- [启动 ZooKeeper 服务器](#启动-zookeeper-服务器)
-- [启动 CLI](#启动-cli)
-- [停止 ZooKeeper 服务器](#停止-zookeeper-服务器)
-
-
-
-在安装 ZooKeeper 之前,请确保你的系统是在以下任一操作系统上运行:
-
-- **任意 Linux OS** - 支持开发和部署。适合演示应用程序。
-- **Windows OS** - 仅支持开发。
-- **Mac OS** - 仅支持开发。
-
-安装步骤如下:
-
-## 下载解压 ZooKeeper
-
-进入官方下载地址:http://zookeeper.apache.org/releases.html#download ,选择合适版本。
-
-解压到本地:
-
-```
-$ tar -zxf zookeeper-3.4.6.tar.gz
-$ cd zookeeper-3.4.6
-```
-
-## 创建配置文件
-
-你必须创建 `conf/zoo.cfg` 文件,否则启动时会提示你没有此文件。
-
-初次尝试,不妨直接使用 Kafka 提供的模板配置文件 `conf/zoo_sample.cfg`:
-
-```
-$ cp conf/zoo_sample.cfg conf/zoo.cfg
-```
-
-## 启动 ZooKeeper 服务器
-
-执行以下命令
-
-```
-$ bin/zkServer.sh start
-```
-
-执行此命令后,你将收到以下响应
-
-```
-$ JMX enabled by default
-$ Using config: /Users/../zookeeper-3.4.6/bin/../conf/zoo.cfg
-$ Starting zookeeper ... STARTED
-```
-
-## 启动 CLI
-
-键入以下命令
-
-```
-$ bin/zkCli.sh
-```
-
-键入上述命令后,将连接到 ZooKeeper 服务器,你应该得到以下响应。
-
-```
-Connecting to localhost:2181
-................
-................
-................
-Welcome to ZooKeeper!
-................
-................
-WATCHER::
-WatchedEvent state:SyncConnected type: None path:null
-[zk: localhost:2181(CONNECTED) 0]
-```
-
-## 停止 ZooKeeper 服务器
-
-连接服务器并执行所有操作后,可以使用以下命令停止 zookeeper 服务器。
-
-```
-$ bin/zkServer.sh stop
-```
-
-> 本节安装内容参考:[Zookeeper 安装](https://www.w3cschool.cn/zookeeper/zookeeper_installation.html)
-
-## 更多内容
-
-- **引申**
- - [操作系统、运维部署总结系列](https://github.com/dunwu/OS)
diff --git a/docs/mac.md b/docs/mac.md
deleted file mode 100644
index 0637f620..00000000
--- a/docs/mac.md
+++ /dev/null
@@ -1,324 +0,0 @@
----
-title: Mac
-date: 2019-03-06
----
-
-# Mac
-
-## 基本操作
-
-### 软件管理
-
-dmg 格式:双击安装包,然后拖到 applications 文件夹下即可。
-
-### 浏览器
-
-#### 更改默认搜索引擎
-
-选择「偏好设置--\>搜索--\>搜索引擎--\>Google」。
-
-#### 导入 chrome 浏览器的书签
-
-选择「文件-->导入自--> Google Chrome」,然后选择要导入的项目。
-
-#### 快捷键
-
-Command + R 刷新
-
-#### 上方显示书签栏/收藏栏
-
-选择「显示--> 显示个人收藏栏」。
-
-#### 关闭软件的右上角通知
-
-在 Mac 系统中有对通知的设置,打开系统偏好设置 — 通知 找到 QQ,然后将 QQ 提示样式设置成无即可。
-
-#### 复制文件/文件夹路径
-
-- OS X 10.11 系统,选中文件夹,「cmd +Option +c」 复制文件夹路径,cmd+v 粘贴。
- 之前的系统,利用 Administrator 创建一个到右键菜单,然后到设置里面设置快捷键。具体操作请百度。
-
-#### 打开来自身份不明的开发者的应用程序
-
-在应用程序文件夹,按住 control 键的同时打开应用程序。
-
-#### 复制文件路径
-
-- 选择文件/文件夹按 Command+C 复制,在终端中 Command+V 粘贴即可。
-
-- 如果只是想在 Finder 中看到文件的路径, 并方便切换层级, Finder 内置了「显示路径栏」的功能, 并配置了快捷键(Option+Cmd+P). 如下图所示:
-
-20161124-184148.png
-
-参考链接:
-
-- [https://www.zhihu.com/question/22883229]
-
-### 隐藏和取消隐藏 Mac App Store 中的已购项目
-
-### Mac 同时登陆两个 QQ
-
-在已经打开的 QQ 中,按住「command + N」即可。
-
-## 系统便好设置
-
-### 语音播报
-
-打开「系统便好设置-->辅助功能-->语音」,即可设置不同国家的语言。
-
-勾选上图中的红框部分,可以设置全局快捷键。这样的话,在任何一个软件当中,按下「 option+esc」时,就会朗读选中的文本。
-
-### 调整字体大小
-
-Mac 调整字体大小:「系统偏好设置 -> 显示器 -> 缩放」。如下图:
-
-### 如何分别设置 Mac 的鼠标和触控板的滚动方向
-
-很多人习惯鼠标使用相反的滚动方向,而触控板类似 iPad 那样的自然滚动,问如何设置,当时我的回答是不知道,因为目前 OS X 的系统设置里,鼠标和触控板的设置是统一
-的。今天发现了一个免费的软件 Scroll Reverser,可以实现鼠标和触控板的分别设置。下载地址:
-启动后程序显示在顶部菜单栏,设置简单明了,有需要的用户体验一下吧。
-
-### Touch Bar 自定义
-
-打开「系统偏好设置-键盘」,下面有个自定义控制条。
-
-### 色温调节:夜间模式
-
-iOS9.3 的最明显变化,莫过于苹果在发布会上特意提到的 Night Shift 夜间护眼模式。
-
-### iCloud 邮箱
-
-如果您用于设置 iCloud 的 Apple ID 不以“@icloud.com”、“@me.com”或“@mac.com”结尾,您必须先设置一个“@icloud.com”电子邮件地址,然后才能使用 iCloud“邮件”。
-
-如果您拥有以“@mac.com”或“@me.com”结尾的电子邮件地址,则您已经拥有了名称相同但以“@icloud.com”结尾的等效地址。如果您使用的电子邮件别名以“@mac.com”或“@me.com”结尾,您也将拥有以“@icloud.com”结尾的等效地址。
-
-**操作如下:**
-
-- 在 iOS 设备上,前往“设置”>“iCloud”,开启“邮件”,然后按照屏幕上的说明操作。
-
-- 在 Mac 上,选取 Apple 菜单 >“系统偏好设置”,点按“iCloud”,再选择“邮件”,然后按照屏幕上的说明操作。
-
-PS:创建 iCloud 电子邮件地址后,您无法对其进行更改。
-
-设置 @icloud.com 电子邮件地址后即可用其登录 iCloud。您也可以用创建 iCloud 帐户时所用的 Apple ID 登录。
-
-您可以从以下任意地址发送 iCloud 电子邮件:
-
-您的 iCloud 电子邮件地址(您的帐号名称@icloud.com)
-
-别名
-
-参考链接:
-
-**直接注册以@icloud.com 结尾的 Apple ID:**
-
-参考链接:
-
-## PodCast
-
-PodCast 中文翻译为播客,是一种特殊的音频 or 视频节目。PodCast 这个单词是由 iPod+Broadcast 这两个单词组成的。
-
-PodCast 可以在 iTunes 中收听。
-
-## others
-
-### 词典
-
-系统有一个自带应用「词典」,可以进行单词的查询。
-
-### 如何解决 MAC 软件(dmg,akp,app)出现程序已损坏的提示
-
-「xxx.app 已损坏,打不开.你应该将它移到废纸篓」,并非你安装的软件已损坏,而是 Mac 系统的安全设置问题,因为这些应用都是破解或者汉化的,那么解决方法就是临时改变 Mac 系统安全设置。
-
-出现这个问题的解决方法:修改系统配置:系统偏好设置... -> 安全性与隐私。修改为任何来源。
-
-如果没有这个选项的话(macOS Sierra 10.12),打开终端,执行:
-
-```bash
-sudo spctl --master-disable
-```
-
-即可。
-
-参考链接:
-
-- [Max OS-[xxx.app 已损坏,打不开.你应该将它移到废纸篓]](http://www.jianshu.com/p/379b49b88df9)
-
-- [如何解决 MAC 软件(dmg,akp,app)出现程序已损坏的提示](http://www.yunrui.co/25693.html)
-
-备注:这个链接里的各种资源都很不错啊。
-
-#### 终端
-
-#### 在 Finder 的当前目录打开终端
-
-在 Finder 打开 terminal 终端这个功能其实是有的,但是系统默认没有打开。我们可以通过如下方法将其打开:
-
-进入系统偏好设置->键盘->快捷键->服务。
-
-在右边新建位于文件夹位置的终端窗口上打勾。
-
-如此设置后,在 Finder 中右击某文件,在出现的菜单中找到服务,然后点击新建位于文件夹位置的终端窗口即可!
-
-## Mac 常用快捷键
-
-### Finder
-
-| 快捷键 | 作用 | 备注 |
-| :------------------ | :------------------- | :----------------- |
-| Shift + Command + G | 前往指定路径的文件夹 | 包括隐藏文件夹 |
-| Shift + Command + . | 显示隐藏文件、文件夹 | 再按一次,恢复隐藏 |
-| Command + ↑ | 返回上一层 | |
-| Command + ↓ | 进入当前文件夹 | |
-
-### 编辑
-
-**删除文字**:
-
-| 快捷键 | 作用 | 备注 |
-| :----------------------- | :--------------------- | :---------------------------- |
-| delete | 删除光标的前一个字符 | 相当于 Windows 键盘上的退格键 |
-| fn + delete | 删除光标的后一个字符 | |
-| option + delete | 删除光标之前的一个单词 | 英文有效 |
-| **command + delete** | 删除光标之前的整行内容 | 【荐】 |
-| command + delete | 在 finder 中删掉该文件 | |
-| shift + command + delete | 清空回收站 | |
-
-**剪切文件**:
-
-首先选中文件,按 Command+C 复制文件;然后按「Command + Option + V」剪切文件。
-
-备注:Command+X 只能剪切文字文本,不要混淆了。
-
-## Mac 用户必须知道的 15 组快捷键
-
-> 参考链接:[《轻松玩 Mac》第 6 期:Mac 用户必须知道的 15 组快捷键](http://v.youku.com/v_show/id_XNDE4MzM0NDgw.html)
-
-### 「space」键:快速预览
-
-选中文件后, 不需要启动任何应用程序,使用「space」空格键可进行快速预览,再次按下「space」空格键取消预览。
-
-可以预览 mp3、视频、pdf 等文件。
-
-我们还可以**选中多张图片**, 然后按「space」键,就可以同时对比预览多张图片。这一点,很赞。
-
-### 改名
-
-选中文件/文件夹后,按 enter 键,就可以改名了。
-
-### 「command + I」键:查看文件属性
-
-- 选中文件后,按「command + I」键,可以查看文件的各种属性。
-
-- 选中**文件夹**后,按「command + I」键,可以查看文件夹的大小。【荐】
-
-### 切换输入法
-
-「control + space」
-
-### 打开 spotlight 搜索框
-
-spotlight 是系统自带的软件,搜索功能不是很强大。我们一般都会用第三方的 Alfred 软件。
-
-### 编辑相关
-
-Cmd+C、Cmd+V、Cmd+X、Cmd+A、Cmd+Z。
-
-### 翻页和光标
-
-- 「control + ↑」:将光标定位到文章的最开头(翻页到文档的最上方)
-
-- 「control + ↓」:将光标定位到文章的最末尾(翻页到文档的最下方)
-
-- 「control + ←」:将光标定位到当前行的最左侧
-
-- 「control + →」:将光标定位到当前行的最右侧
-
-### 「command + shift + Y」:将文字快速保存到便笺
-
-选中你想要的内容(例如文字、链接等),然后按下 command + shift + Y」,那么你选中的内容就会快速保存到系统自带的「便笺」软件中。
-
-如果你想临时性的保存一段内容,这个操作很实用。
-
-### 程序相关
-
-- 「command + Q」:快速退出程序
-
-- 「command + tab」:切换程序
-
-- 「command + H」:隐藏当前应用程序。这是一个有趣的快捷键。
-
-- 「command + ,」:打开当前应用程序的「偏好设置」。
-
-### 窗口相关
-
-- 「command + N」:新建一个当前应用程序的窗口
-
-- 「command + `」:在当前应用程序的不同窗口之间切换【很实用】
-
-我们知道,「command + tab」是在不同的软件之间切换。但你不知道的是,「command + `」是在同一个软件的不同窗口之间切换。
-
-- 「command + M」:将当前窗口最小化
-
-- 「command + W」:关闭当前窗口
-
-### 浏览器相关
-
-- 「command + T」:浏览器中,新建一个标签
-
-- 「command + W」:关闭当前标签
-
-* 「command + R」:强制刷新。
-
-- 「command + L」:定位到地址栏。【重要】
-
-### 截图相关
-
-- 「command + shift + 3」:截全屏(对整个屏幕截图)。
-
-### 声音相关
-
-选中文字后,按住「ctrl + esc」键,会将文字进行朗读。(我发现,在触控条版的 mac 上,并没有生效)
-
-### Dock 栏相关
-
-- 「option + command + D」:隐藏 dock 栏
-
-### 强制推出
-
-> 强制退出的快捷键非常重要
-
-- 「option + command + esc」:打开强制退出的窗口
-
-### option 相关
-
-> 强烈推荐
-
-- 「option + command + H」:隐藏除当前应用程序之外的其他应用程序
-
-- 在文本中,按住「option」键,配合鼠标的选中,可以进行块状文字选取。
-
-- 「option + command + W」:快速关闭当前应用程序的所有窗口。【很实用】
-
-比如说,你一次性打开了很多文件的详情,然后就可以通过此快捷键,将这些窗口一次性关闭。
-
-- 「option + command + I」:查看多个文件的总的属性。
-
-* 打开 launchpad,按住「option」键,可以快速卸载应用程序。
-
-* 在 dock 栏,右键点击软件图标,同时按住「option」键,就可以**强制退出**该软件。【重要】
-
-- 在 Safari 浏览器中,按住「option + command + Q」退出 Safari。等下次进入 Safari 的时候,上次退出时的网址会自动被打开。【实用】
-
-### 推荐一个软件:CheatSheet
-
-打开 CheatSheet 后,长按 command 键,会弹出当前应用程序的所有快捷键。我们还可以对这些快捷键进行保存。
-
-## :books: 学习资源
-
-- [Awesome Mac](https://github.com/jaywcjlove/awesome-mac)
-- [awesome-macos-command-line](https://github.com/herrbischoff/awesome-macos-command-line)
-
-## :door: 传送门
-
-| [回首頁](https://github.com/dunwu/blog) |
diff --git a/docs/mac/soft/ruby-install.md b/docs/mac/soft/ruby-install.md
new file mode 100644
index 00000000..4138881a
--- /dev/null
+++ b/docs/mac/soft/ruby-install.md
@@ -0,0 +1,65 @@
+# 安装 Ruby
+
+## 安装 rvm
+
+### 下载安装 rvm
+
+- 先安装好 RVM
+- RVM 是一个便捷的多版本 Ruby 环境的管理和切换工具
+ 官网:[https://rvm.io/](https://links.jianshu.com/go?to=https%3A%2F%2Frvm.io%2F)
+- 在终端控制台命令:
+ $ curl -sSL [https://get.rvm.io](https://links.jianshu.com/go?to=https%3A%2F%2Fget.rvm.io) | bash -s stable 之后按回车键
+- 截止到目前 最新的版本是 1.29.9
+- 如下所示:
+
+```shell
+:~ admin$ curl -sSL https://get.rvm.io | bash -s stable
+Downloading https://github.com/rvm/rvm/archive/1.29.1.tar.gz
+Downloading https://github.com/rvm/rvm/releases/download/1.29.1/1.29.1.tar.gz.asc
+Found PGP signature at: 'https://github.com/rvm/rvm/releases/download/1.29.1/1.29.1.tar.gz.asc',
+but no GPG software exists to validate it, skipping.
+
+Installing RVM to /Users/admin/.rvm/
+ Adding rvm PATH line to /Users/admin/.profile /Users/admin/.mkshrc /Users/admin/.bashrc /Users/admin/.zshrc.
+ Adding rvm loading line to /Users/admin/.profile /Users/admin/.bash_profile /Users/admin/.zlogin.
+Installation of RVM in /Users/admin/.rvm/ is almost complete:
+
+ * To start using RVM you need to run `source /Users/admin/.rvm/scripts/rvm`
+ in all your open shell windows, in rare cases you need to reopen all shell windows.
+
+# admin,
+#
+# Thank you for using RVM!
+# We sincerely hope that RVM helps to make your life easier and more enjoyable!!!
+#
+# ~Wayne, Michal & team.
+
+In case of problems: https://rvm.io/help and https://twitter.com/rvm_io
+```
+
+等待一两分钟,成功安装好 RVM。
+
+### 设置环境变量
+
+
+
+```shell
+# 1.2 然后,载入 RVM 环境:
+$ source /etc/profile.d/rvm.sh
+$ sudo chmod -R 777 /usr/local/rvm/archives
+
+# 1.3 修改 RVM 下载 Ruby 的源,到 Ruby China 的镜像
+$ echo "ruby_url=https://cache.ruby-china.com/pub/ruby" > /usr/local/rvm/user/db
+$ rvm install 2.7.0 --disable-binary
+
+// 如下所示:
+AdmindeiMac-4:~ admin$ source ~/.rvm/scripts/rvm
+AdmindeiMac-4:~ admin$ echo "ruby_url=https://cache.ruby-china.org/pub/ruby" > ~/.rvm/user/db
+AdmindeiMac-4:~ admin$ rvm -v
+rvm 1.29.9 (latest) by Michal Papis, Piotr Kuczynski, Wayne E. Seguin [https://rvm.io/]
+如果能显示版本号,则安装成功。
+```
+
+## 参考资料
+
+- [MAC_Ruby 安装](https://www.jianshu.com/p/c073e6fc01f5)
\ No newline at end of file
diff --git a/docs/package.json b/docs/package.json
index 317614bb..cfccfcb4 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -1,9 +1,30 @@
{
"name": "linux-tutorial",
"version": "1.0.0",
+ "private": true,
"scripts": {
- "start": "docsify serve ./"
+ "clean": "rimraf dist && rimraf .temp",
+ "build": "npm run clean && vuepress build ./ --temp .temp",
+ "start": "vuepress dev ./ --temp .temp",
+ "lint": "markdownlint -r markdownlint-rule-emphasis-style -c ./.markdownlint.json **/*.md -i node_modules",
+ "lint:fix": "markdownlint -f -r markdownlint-rule-emphasis-style -c ./.markdownlint.json **/*.md -i node_modules",
+ "show-help": "vuepress --help",
+ "view-info": "vuepress view-info ./ --temp .temp"
},
- "dependencies": {},
- "devDependencies": {}
+ "devDependencies": {
+ "@vuepress/plugin-active-header-links": "^1.8.2",
+ "@vuepress/plugin-back-to-top": "^1.8.2",
+ "@vuepress/plugin-medium-zoom": "^1.8.2",
+ "@vuepress/plugin-pwa": "^1.8.2",
+ "@vuepress/theme-vue": "^1.8.2",
+ "markdownlint-cli": "^0.25.0",
+ "markdownlint-rule-emphasis-style": "^1.0.1",
+ "rimraf": "^3.0.1",
+ "vue-toasted": "^1.1.25",
+ "vuepress": "^1.8.2",
+ "vuepress-plugin-flowchart": "^1.4.2"
+ },
+ "dependencies": {
+ "moment": "^2.29.1"
+ }
}
diff --git a/docs/windows.md b/docs/windows.md
deleted file mode 100644
index 7ab5bf9e..00000000
--- a/docs/windows.md
+++ /dev/null
@@ -1,130 +0,0 @@
----
-title: 程序员玩转 Windows
-categories: ['os']
-tags: ['os', 'windows']
-date: 2019-03-22 15:53
----
-
-# 程序员玩转 Windows
-
-
-
-- [软件](#软件)
- - [视频音频](#视频音频)
- - [压缩](#压缩)
- - [文件管理](#文件管理)
- - [开发](#开发)
- - [编辑器](#编辑器)
- - [文档](#文档)
- - [效率提升](#效率提升)
- - [办公](#办公)
- - [个性化](#个性化)
-- [参考资料](#参考资料)
-
-
-
-## 软件
-
-> 扩展阅读:
->
-> - [Awesome Windows](https://github.com/Awesome-Windows/Awesome/blob/master/README-cn.md)
-> - [best-windows-apps](https://github.com/stackia/best-windows-apps)
-
-### 视频音频
-
-- [Musicbee](http://getmusicbee.com/) - 类似 iTunes,但比 iTunes 更好用。
-- [ScreenToGif](http://www.screentogif.com/) - 它允许你录制屏幕的一部分区域并保存为 gif 或视频。
-- [PotPlayer](http://potplayer.daum.net/) - 多媒体播放器,具有广泛的编解码器集合,它还为用户提供大量配置选项。
-- [射手影音播放器](http://www.splayer.org/) - 来自射手网,小巧开源,首创自动匹配字幕功能。
-
-### 压缩
-
-- [7-Zip](http://www.7-zip.org/) - 用于处理压缩包的开源 Windows 实用程序。完美支持 7z,ZIP,GZIP,BZIP2 和 TAR 的全部特性,其他格式也可解压缩。
-- [WinRAR](http://www.rarlab.com/) - 强大的归档管理器。 它可以备份您的数据并减小电子邮件附件的大小,解压缩 RAR,ZIP 和其他文件。
-
-### 文件管理
-
-- [Clover](http://en.ejie.me/) - 为资源管理器加上多标签功能。
-- [Total Commander](http://www.ghisler.com/) - 老牌、功能异常强大的文件管理增强软件。
-- [Q-Dir](http://www.softwareok.com/?seite=Freeware/Q-Dir) - 轻量级的文件管理器,各种布局视图切换灵活,默认四个小窗口组成一个大窗口,操作快捷。软件虽小,粉丝忠诚。
-- [WoX](https://github.com/Wox-launcher/Wox) - 新一代文件定位工具,堪称 Windows 上的 Alfred。
-- [Everything](http://www.voidtools.com/) - 最快的文件/文件夹搜索工具, 通过名称搜索。
-- [Listary](http://www.listary.com/) - 非常优秀的 Windows 文件浏览和搜索增强工具。
-- Beyond Compare - 好用又万能的文件对比工具。
-- [CCleaner](https://www.piriform.com/ccleaner/download) - 如果你有系统洁癖,那一定要选择一款干净、良心、老牌的清洁软件。
-- [chocolatey](https://chocolatey.org/) - 包管理器
-- [Ninite](https://ninite.com/) - 最简单,最快速的更新或安装软件的方式。
-- [Recuva](http://www.piriform.com/RECUVA) - 来自 piriform 梨子公司产品,免费的数据恢复工具。
-- [Launchy](http://www.launchy.net/):自由的跨平台工具,帮助你忘记开始菜单、桌面图标甚至文件管理器。
-
-### 开发
-
-- [Fiddler](http://www.telerik.com/fiddler) - web 调试代理工具。
-- [Postman](https://www.getpostman.com/postman) - 适合 API 开发的完整工具链,最常用的 REST 客户端。
-- [SourceTree](https://www.sourcetreeapp.com/) - 一个免费的 Git & Mercurial 客户端。
-- [TortoiseSVN](https://tortoisesvn.net/) - Subversion(SVN)的图形客户端
-- [Wireshark](https://www.wireshark.org/) - 一个网络协议分析工具。
-- Switchhosts
-- [Cmder](https://github.com/cmderdev/cmder) - 控制台模拟器包。扩展阅读:[Win 下必备神器之 Cmder](https://www.jeffjade.com/2016/01/13/2016-01-13-windows-software-cmder/)
-- [Babun](http://babun.github.io/) - 基于 Cygwin,用于替代 Windows shell。
-
-### 编辑器
-
-- [JetBrain IDE 系列](http://www.jetbrains.com/) - 真香!
-- [Visual Studio Code](https://code.visualstudio.com/) - 用于构建和调试现代 Web 和云应用程序。
-- [Eclipse](https://eclipse.org/downloads/) - 一款功能强大的 IDE。
-- [Visual Studio](https://www.visualstudio.com/vs/) - 微软官方的 IDE,通过插件可支持大量编程语言。
-- [NetBeans IDE](https://netbeans.org/) - 免费开源的 IDE。
-- [Typora](https://www.typora.io/) - 个人觉得最好用的 Markdown 编辑器。
-- [Cmd Markdown](https://www.zybuluo.com/cmd/) - 跨平台优秀 Markdown 编辑器,本文即用其所写。
-- [Notepad++](https://notepad-plus-plus.org/) - 一款支持多种编程语言的源码编辑器。
-- [Notepad2](http://www.flos-freeware.ch/notepad2.html) - 用于替代默认文本编辑器的轻量快速的编辑器,拥有众多有用的功能。
-- [Sublime Text 3](http://www.sublimetext.com/3) - 高级文本编辑器。
-- [Atom](https://atom.io/) - 面向 21 世纪的极客文本编辑器。
-
-### 文档
-
-- [Microsoft Office](http://www.office.com/) - 微软办公软件。
-- [WPS Office](https://www.wps.com/office-free) - 金山免费办公软件。
-- [Calibre](http://calibre-ebook.com/) - 用于电子书管理和转换的强大软件。
-- [福昕阅读器](http://www.foxitsoftware.cn/products/reader/) - 在全球拥有大量用户,最优秀的国产软件之一。Ribbon 界面,支持手写签名、插入印章等。
-
-### 效率提升
-
-**【笔记】**
-
-- [XMind](http://www.xmind.net/) - 优秀的思维导图。
-- [OneNote](https://www.onenote.com/) - Windows 下综合评价非常高的笔记应用。
-- [印象笔记](http://www.yinxiang.com/) - 老牌跨平台笔记工具,国际版 Evernote。一家立志于做百年公司的企业,安全、可靠。
-- [为知笔记](http://www.wiz.cn/index.html) - 越来越好的笔记应用,记录、查阅一切有价值的信息,同样跨平台支持。
-- [有道云笔记](http://note.youdao.com/) - 网易旗下笔记工具,同样跨主流平台支持,文字、手写、录音、拍照多种记录方式,支持任意附件格式。
-- [ShareX](https://getsharex.com/) - 你要的所有与截图、录屏相关的功能,这里都有了。
-
-【快捷键】
-
-- [AutoHotkey](https://autohotkey.com/) - Windows 平台的终极自动化脚本语言。
-
-> 技巧:
->
-> - https://www.jeffjade.com/2016/03/11/2016-03-11-autohotkey/
-> - https://www.autohotkey.com/boards/viewtopic.php?f=29&t=4296
-
-### 办公
-
-- [有道词典](http://cidian.youdao.com/index.html) - 最好用的免费全能翻译软件。
-- [Outlook](http://office.microsoft.com/zh-cn/outlook/) - 大名鼎鼎的 Microsoft Office 组件之一,除了电子邮件,还包含了日历、任务管理、联系人、记事本等功能。
-- [Gmail](http://www.gmail.com/) - 功能上可以称为业界标杆,用户数量世界第一,或许你真的找不到比它更好的邮件系统。
-- [Chrome](https://www.google.com/intl/zh-CN/chrome/browser/) - 最好的浏览器。
-- [Teamviewer](http://www.teamviewer.com/Zhcn/index.aspx) - 专业、功能强大的远程控制软件。使用简单,对个人用户免费。
-
-### 个性化
-
-- [TranslucentTB](https://github.com/TranslucentTB/TranslucentTB) - 透明化你的 Windows 任务栏。
-- [QTTabBar](http://qttabbar.wikidot.com/) - 通过多标签和额外的文件夹视图扩展资源管理器的功能。
-- [Fences](https://www.stardock.com/products/fences/) - 管理桌面快捷方式。
-
-## 参考资料
-
-- https://github.com/Awesome-Windows/Awesome/blob/master/README-cn.md
-- https://love.appinn.com/
-- https://github.com/stackia/best-windows-apps
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
new file mode 100644
index 00000000..3ebd471c
--- /dev/null
+++ b/scripts/deploy.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env sh
+
+# ------------------------------------------------------------------------------
+# gh-pages 部署脚本
+# @author Zhang Peng
+# @since 2020/2/10
+# ------------------------------------------------------------------------------
+
+# 装载其它库
+ROOT_DIR=$(cd `dirname $0`/..; pwd)
+
+# 确保脚本抛出遇到的错误
+set -e
+
+cd ${ROOT_DIR}/docs
+
+# 生成静态文件
+npm install
+npm run build
+
+# 进入生成的文件夹
+cd dist
+
+# 如果是发布到自定义域名
+# echo 'www.example.com' > CNAME
+
+git init
+git checkout -b gh-pages && git add .
+git commit -m 'deploy'
+
+# 如果发布到 https://.github.io/
+if [[ ${GITHUB_TOKEN} && ${GITEE_TOKEN} ]]; then
+ echo "使用 token 公钥部署 gh-pages"
+ # ${GITHUB_TOKEN} 是 Github 私人令牌;${GITEE_TOKEN} 是 Gitee 私人令牌
+ # ${GITHUB_TOKEN} 和 ${GITEE_TOKEN} 都是环境变量;travis-ci 构建时会传入变量
+ git push --force --quiet "https://dunwu:${GITHUB_TOKEN}@github.com/dunwu/linux-tutorial.git" gh-pages
+ git push --force --quiet "https://turnon:${GITEE_TOKEN}@gitee.com/turnon/linux-tutorial.git" gh-pages
+else
+ echo "使用 ssh 公钥部署 gh-pages"
+ git push -f git@github.com:dunwu/linux-tutorial.git gh-pages
+ git push -f git@gitee.com:turnon/linux-tutorial.git gh-pages
+fi
+
+cd ${ROOT_DIR}
diff --git a/scripts/gitpush.sh b/scripts/gitpush.sh
deleted file mode 100644
index ec14d5a9..00000000
--- a/scripts/gitpush.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-
-cd ..
-git push github master
-git push gitee master