├── Development.md
├── LICENSE
├── README.md
├── Rules.md
├── img
└── screenshot1.png
├── install.sh
├── menu.toml
├── modules.d
├── 000-menu.toml
├── 010-system_info.toml
├── 020-test_tool.toml
├── 030-system_reinstall.toml
├── 040-system_manage.toml
├── 060-network_tools.toml
├── 070-security_tools.toml
├── 080-app_deployment.toml
└── 090-utility_tools.toml
├── nsk.sh
└── shell_scripts
├── app_deployment
└── alist_manager.sh
├── example.v0.0.1.0417.sh
├── hardware_info
└── disk_test.sh
├── system_manage
├── manage_services.sh
└── terminal_setup.sh
├── system_reinstall
├── installnet.sh
└── reinstall.sh
└── utility_tools
├── auto_mount_disk.sh
├── crontab_management.sh
├── geek_prompt.sh
├── hostname_management.sh
├── ports_management.sh
└── ssh_management.sh
/Development.md:
--------------------------------------------------------------------------------
1 | ## **一、欢迎**
2 |
3 | 感谢你对 NodeScriptKit 的兴趣!本指南将帮助你快速上手开发流程,提交代码并参与项目建设。无论你是修复 Bug、添加功能还是完善文档,我们都欢迎你的贡献。
4 |
5 |
6 | ## **二、环境搭建**
7 |
8 |
9 | ### **前置条件**
10 |
11 |
12 |
13 | * **操作系统**:Linux(推荐 Debian、Ubuntu、CentOS 或 Alpine)。
14 | * **权限**:需要 root 权限运行脚本。
15 | * **工具**:
16 | * `bash`:核心脚本语言。
17 | * `curl` 和 `wget`:用于下载外部资源。
18 | * `git`:用于版本控制。
19 |
20 |
21 | ### **获取代码**
22 |
23 | 克隆仓库:
24 |
25 | ```
26 | git clone git@github.com:NodeSeekDev/NodeScriptKit.git
27 | cd NodeScriptKit
28 | ```
29 |
30 |
31 |
32 | ### **安装依赖**
33 |
34 | 运行以下命令安装基本依赖:
35 |
36 | ```
37 | apt update && apt install -y curl wget git # Debian/Ubuntu
38 | yum install -y curl wget git # CentOS
39 | apk add curl wget git # Alpine
40 | ```
41 |
42 | ## **三、代码结构**
43 |
44 |
45 | * **主文件**:`nodescriptkit.sh`(假设为你的脚本文件名)。
46 | * **核心功能**:
47 | * `display_menu`:主菜单入口。
48 | * `sys_info`:系统信息查询。
49 | * `tcp_tune`:TCP 参数优化。
50 | * 更多模块见脚本注释。
51 | * **外部资源**:部分功能依赖在线脚本(如 `bbr.sh`)。
52 |
53 |
54 | ## **四、开发规范**
55 |
56 |
57 | ### **命名规则**
58 |
59 |
60 |
61 | * **函数名**:小写加下划线,如 `get_system_info`。
62 | * **变量名**:清晰描述用途,如 `ipv4_address`。
63 | * **颜色变量**:使用现有定义,如 `RED`、`GREEN`。
64 |
65 | 具体可阅读脚本 <示例代码>
66 |
67 |
68 | ### **代码风格**
69 |
70 | * **缩进**:使用 2 或 4 个空格(保持一致)。
71 | * **注释**:关键功能需添加简要说明,例如:
72 |
73 |
74 | * **函数名**:小写加下划线,如 `get_system_info`。
75 | * **变量名**:清晰描述用途,如 `ipv4_address`。
76 | * **颜色变量**:使用现有定义,如 `RED`、`GREEN`。
77 |
78 | 具体可阅读脚本 <示例代码>
79 |
80 |
81 | ### **代码风格**
82 | * **缩进**:使用 2 或 4 个空格(保持一致)。
83 | * **注释**:关键功能需添加简要说明,例如:
84 |
85 | ```
86 | # 获取系统运行时间
87 | runtime=$(cat /proc/uptime | awk ...)
88 | ```
89 | 错误处理:使用 danger、success 等函数提示用户:
90 |
91 | ```
92 | success "执行成功!"
93 | danger "请以 root 权限运行脚本!"
94 | ```
95 |
96 | ### **提交要求**
97 |
98 | * **单一目的**:每个 PR 解决一个问题或添加一个功能。
99 | * **提交信息**:
100 | * 格式:`[类别] 描述`,如 `[Fix] 修复 IPv6 获取失败问题`。
101 | * 类别可选:`[Feat]`(新功能)、`[Fix]`(修复)、`[Docs]`(文档)等。
102 |
103 | ## **五、开发流程**
104 |
105 | ### **1. Fork 与分支**
106 |
107 | 1) Fork 仓库。
108 |
109 | 2). 创建功能分支,如:
110 |
111 | ```
112 | git checkout -b feature/add-database-tool
113 | ```
114 |
115 | ### **2. 修改与测试**
116 |
117 | - 基于<示例代码>规范,编辑脚本,添加或优化功能。
118 |
119 | - 本地测试:
120 |
121 | ```
122 | nsk
123 | ```
124 |
125 | - 示例:运行 检查系统信息是否正常输出。
126 | - 实机测试:参考 <测试方法>
127 |
128 | ### **3. 提交代码**
129 |
130 | 1. 提交更改:
131 |
132 | ```
133 | git add .
134 | git commit -m "[Feat] 添加数据库管理工具"
135 | ```
136 |
137 | 2. 推送到远程:
138 |
139 | ```
140 | git push origin feature/add-database-tool
141 | ```
142 |
143 | ### **4. 提交 Pull Request**
144 |
145 | - 在 GitHub 上创建 PR,描述你的改动和测试结果。
146 | - 等待维护者审核。
147 |
148 |
149 | ## **六、测试方法**
150 |
151 | * **环境**:建议使用虚拟机(如 VirtualBox)或 VPS。
152 | * **步骤**:
153 | 1. 运行完整脚本,检查菜单功能。
154 | 2. 测试特定模块,如 `nsk -> 选择分类,测试最终结果符合预期`。
155 | 3. 检查错误日志,确保无异常退出。
156 | * **兼容性**:在不同系统(Debian、CentOS)上验证
157 |
158 |
159 | ## **七、已知问题**
160 | * 部分功能依赖网络,可能因连接问题失败。
161 |
162 | 该部分逐步补充...
163 |
164 |
165 | ## **八、获取帮助**
166 |
167 | * **社区**:加入 [Telegram 频道](https://t.me/NodeSelect) 或 GitHub Discussions。
168 |
169 | 让我们一起让 NodeScriptKit 更强大!
170 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU AFFERO GENERAL PUBLIC LICENSE
2 | Version 3, 19 November 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU Affero General Public License is a free, copyleft license for
11 | software and other kinds of works, specifically designed to ensure
12 | cooperation with the community in the case of network server software.
13 |
14 | The licenses for most software and other practical works are designed
15 | to take away your freedom to share and change the works. By contrast,
16 | our General Public Licenses are intended to guarantee your freedom to
17 | share and change all versions of a program--to make sure it remains free
18 | software for all its users.
19 |
20 | When we speak of free software, we are referring to freedom, not
21 | price. Our General Public Licenses are designed to make sure that you
22 | have the freedom to distribute copies of free software (and charge for
23 | them if you wish), that you receive source code or can get it if you
24 | want it, that you can change the software or use pieces of it in new
25 | free programs, and that you know you can do these things.
26 |
27 | Developers that use our General Public Licenses protect your rights
28 | with two steps: (1) assert copyright on the software, and (2) offer
29 | you this License which gives you legal permission to copy, distribute
30 | and/or modify the software.
31 |
32 | A secondary benefit of defending all users' freedom is that
33 | improvements made in alternate versions of the program, if they
34 | receive widespread use, become available for other developers to
35 | incorporate. Many developers of free software are heartened and
36 | encouraged by the resulting cooperation. However, in the case of
37 | software used on network servers, this result may fail to come about.
38 | The GNU General Public License permits making a modified version and
39 | letting the public access it on a server without ever releasing its
40 | source code to the public.
41 |
42 | The GNU Affero General Public License is designed specifically to
43 | ensure that, in such cases, the modified source code becomes available
44 | to the community. It requires the operator of a network server to
45 | provide the source code of the modified version running there to the
46 | users of that server. Therefore, public use of a modified version, on
47 | a publicly accessible server, gives the public access to the source
48 | code of the modified version.
49 |
50 | An older license, called the Affero General Public License and
51 | published by Affero, was designed to accomplish similar goals. This is
52 | a different license, not a version of the Affero GPL, but Affero has
53 | released a new version of the Affero GPL which permits relicensing under
54 | this license.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | TERMS AND CONDITIONS
60 |
61 | 0. Definitions.
62 |
63 | "This License" refers to version 3 of the GNU Affero General Public License.
64 |
65 | "Copyright" also means copyright-like laws that apply to other kinds of
66 | works, such as semiconductor masks.
67 |
68 | "The Program" refers to any copyrightable work licensed under this
69 | License. Each licensee is addressed as "you". "Licensees" and
70 | "recipients" may be individuals or organizations.
71 |
72 | To "modify" a work means to copy from or adapt all or part of the work
73 | in a fashion requiring copyright permission, other than the making of an
74 | exact copy. The resulting work is called a "modified version" of the
75 | earlier work or a work "based on" the earlier work.
76 |
77 | A "covered work" means either the unmodified Program or a work based
78 | on the Program.
79 |
80 | To "propagate" a work means to do anything with it that, without
81 | permission, would make you directly or secondarily liable for
82 | infringement under applicable copyright law, except executing it on a
83 | computer or modifying a private copy. Propagation includes copying,
84 | distribution (with or without modification), making available to the
85 | public, and in some countries other activities as well.
86 |
87 | To "convey" a work means any kind of propagation that enables other
88 | parties to make or receive copies. Mere interaction with a user through
89 | a computer network, with no transfer of a copy, is not conveying.
90 |
91 | An interactive user interface displays "Appropriate Legal Notices"
92 | to the extent that it includes a convenient and prominently visible
93 | feature that (1) displays an appropriate copyright notice, and (2)
94 | tells the user that there is no warranty for the work (except to the
95 | extent that warranties are provided), that licensees may convey the
96 | work under this License, and how to view a copy of this License. If
97 | the interface presents a list of user commands or options, such as a
98 | menu, a prominent item in the list meets this criterion.
99 |
100 | 1. Source Code.
101 |
102 | The "source code" for a work means the preferred form of the work
103 | for making modifications to it. "Object code" means any non-source
104 | form of a work.
105 |
106 | A "Standard Interface" means an interface that either is an official
107 | standard defined by a recognized standards body, or, in the case of
108 | interfaces specified for a particular programming language, one that
109 | is widely used among developers working in that language.
110 |
111 | The "System Libraries" of an executable work include anything, other
112 | than the work as a whole, that (a) is included in the normal form of
113 | packaging a Major Component, but which is not part of that Major
114 | Component, and (b) serves only to enable use of the work with that
115 | Major Component, or to implement a Standard Interface for which an
116 | implementation is available to the public in source code form. A
117 | "Major Component", in this context, means a major essential component
118 | (kernel, window system, and so on) of the specific operating system
119 | (if any) on which the executable work runs, or a compiler used to
120 | produce the work, or an object code interpreter used to run it.
121 |
122 | The "Corresponding Source" for a work in object code form means all
123 | the source code needed to generate, install, and (for an executable
124 | work) run the object code and to modify the work, including scripts to
125 | control those activities. However, it does not include the work's
126 | System Libraries, or general-purpose tools or generally available free
127 | programs which are used unmodified in performing those activities but
128 | which are not part of the work. For example, Corresponding Source
129 | includes interface definition files associated with source files for
130 | the work, and the source code for shared libraries and dynamically
131 | linked subprograms that the work is specifically designed to require,
132 | such as by intimate data communication or control flow between those
133 | subprograms and other parts of the work.
134 |
135 | The Corresponding Source need not include anything that users
136 | can regenerate automatically from other parts of the Corresponding
137 | Source.
138 |
139 | The Corresponding Source for a work in source code form is that
140 | same work.
141 |
142 | 2. Basic Permissions.
143 |
144 | All rights granted under this License are granted for the term of
145 | copyright on the Program, and are irrevocable provided the stated
146 | conditions are met. This License explicitly affirms your unlimited
147 | permission to run the unmodified Program. The output from running a
148 | covered work is covered by this License only if the output, given its
149 | content, constitutes a covered work. This License acknowledges your
150 | rights of fair use or other equivalent, as provided by copyright law.
151 |
152 | You may make, run and propagate covered works that you do not
153 | convey, without conditions so long as your license otherwise remains
154 | in force. You may convey covered works to others for the sole purpose
155 | of having them make modifications exclusively for you, or provide you
156 | with facilities for running those works, provided that you comply with
157 | the terms of this License in conveying all material for which you do
158 | not control copyright. Those thus making or running the covered works
159 | for you must do so exclusively on your behalf, under your direction
160 | and control, on terms that prohibit them from making any copies of
161 | your copyrighted material outside their relationship with you.
162 |
163 | Conveying under any other circumstances is permitted solely under
164 | the conditions stated below. Sublicensing is not allowed; section 10
165 | makes it unnecessary.
166 |
167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168 |
169 | No covered work shall be deemed part of an effective technological
170 | measure under any applicable law fulfilling obligations under article
171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
172 | similar laws prohibiting or restricting circumvention of such
173 | measures.
174 |
175 | When you convey a covered work, you waive any legal power to forbid
176 | circumvention of technological measures to the extent such circumvention
177 | is effected by exercising rights under this License with respect to
178 | the covered work, and you disclaim any intention to limit operation or
179 | modification of the work as a means of enforcing, against the work's
180 | users, your or third parties' legal rights to forbid circumvention of
181 | technological measures.
182 |
183 | 4. Conveying Verbatim Copies.
184 |
185 | You may convey verbatim copies of the Program's source code as you
186 | receive it, in any medium, provided that you conspicuously and
187 | appropriately publish on each copy an appropriate copyright notice;
188 | keep intact all notices stating that this License and any
189 | non-permissive terms added in accord with section 7 apply to the code;
190 | keep intact all notices of the absence of any warranty; and give all
191 | recipients a copy of this License along with the Program.
192 |
193 | You may charge any price or no price for each copy that you convey,
194 | and you may offer support or warranty protection for a fee.
195 |
196 | 5. Conveying Modified Source Versions.
197 |
198 | You may convey a work based on the Program, or the modifications to
199 | produce it from the Program, in the form of source code under the
200 | terms of section 4, provided that you also meet all of these conditions:
201 |
202 | a) The work must carry prominent notices stating that you modified
203 | it, and giving a relevant date.
204 |
205 | b) The work must carry prominent notices stating that it is
206 | released under this License and any conditions added under section
207 | 7. This requirement modifies the requirement in section 4 to
208 | "keep intact all notices".
209 |
210 | c) You must license the entire work, as a whole, under this
211 | License to anyone who comes into possession of a copy. This
212 | License will therefore apply, along with any applicable section 7
213 | additional terms, to the whole of the work, and all its parts,
214 | regardless of how they are packaged. This License gives no
215 | permission to license the work in any other way, but it does not
216 | invalidate such permission if you have separately received it.
217 |
218 | d) If the work has interactive user interfaces, each must display
219 | Appropriate Legal Notices; however, if the Program has interactive
220 | interfaces that do not display Appropriate Legal Notices, your
221 | work need not make them do so.
222 |
223 | A compilation of a covered work with other separate and independent
224 | works, which are not by their nature extensions of the covered work,
225 | and which are not combined with it such as to form a larger program,
226 | in or on a volume of a storage or distribution medium, is called an
227 | "aggregate" if the compilation and its resulting copyright are not
228 | used to limit the access or legal rights of the compilation's users
229 | beyond what the individual works permit. Inclusion of a covered work
230 | in an aggregate does not cause this License to apply to the other
231 | parts of the aggregate.
232 |
233 | 6. Conveying Non-Source Forms.
234 |
235 | You may convey a covered work in object code form under the terms
236 | of sections 4 and 5, provided that you also convey the
237 | machine-readable Corresponding Source under the terms of this License,
238 | in one of these ways:
239 |
240 | a) Convey the object code in, or embodied in, a physical product
241 | (including a physical distribution medium), accompanied by the
242 | Corresponding Source fixed on a durable physical medium
243 | customarily used for software interchange.
244 |
245 | b) Convey the object code in, or embodied in, a physical product
246 | (including a physical distribution medium), accompanied by a
247 | written offer, valid for at least three years and valid for as
248 | long as you offer spare parts or customer support for that product
249 | model, to give anyone who possesses the object code either (1) a
250 | copy of the Corresponding Source for all the software in the
251 | product that is covered by this License, on a durable physical
252 | medium customarily used for software interchange, for a price no
253 | more than your reasonable cost of physically performing this
254 | conveying of source, or (2) access to copy the
255 | Corresponding Source from a network server at no charge.
256 |
257 | c) Convey individual copies of the object code with a copy of the
258 | written offer to provide the Corresponding Source. This
259 | alternative is allowed only occasionally and noncommercially, and
260 | only if you received the object code with such an offer, in accord
261 | with subsection 6b.
262 |
263 | d) Convey the object code by offering access from a designated
264 | place (gratis or for a charge), and offer equivalent access to the
265 | Corresponding Source in the same way through the same place at no
266 | further charge. You need not require recipients to copy the
267 | Corresponding Source along with the object code. If the place to
268 | copy the object code is a network server, the Corresponding Source
269 | may be on a different server (operated by you or a third party)
270 | that supports equivalent copying facilities, provided you maintain
271 | clear directions next to the object code saying where to find the
272 | Corresponding Source. Regardless of what server hosts the
273 | Corresponding Source, you remain obligated to ensure that it is
274 | available for as long as needed to satisfy these requirements.
275 |
276 | e) Convey the object code using peer-to-peer transmission, provided
277 | you inform other peers where the object code and Corresponding
278 | Source of the work are being offered to the general public at no
279 | charge under subsection 6d.
280 |
281 | A separable portion of the object code, whose source code is excluded
282 | from the Corresponding Source as a System Library, need not be
283 | included in conveying the object code work.
284 |
285 | A "User Product" is either (1) a "consumer product", which means any
286 | tangible personal property which is normally used for personal, family,
287 | or household purposes, or (2) anything designed or sold for incorporation
288 | into a dwelling. In determining whether a product is a consumer product,
289 | doubtful cases shall be resolved in favor of coverage. For a particular
290 | product received by a particular user, "normally used" refers to a
291 | typical or common use of that class of product, regardless of the status
292 | of the particular user or of the way in which the particular user
293 | actually uses, or expects or is expected to use, the product. A product
294 | is a consumer product regardless of whether the product has substantial
295 | commercial, industrial or non-consumer uses, unless such uses represent
296 | the only significant mode of use of the product.
297 |
298 | "Installation Information" for a User Product means any methods,
299 | procedures, authorization keys, or other information required to install
300 | and execute modified versions of a covered work in that User Product from
301 | a modified version of its Corresponding Source. The information must
302 | suffice to ensure that the continued functioning of the modified object
303 | code is in no case prevented or interfered with solely because
304 | modification has been made.
305 |
306 | If you convey an object code work under this section in, or with, or
307 | specifically for use in, a User Product, and the conveying occurs as
308 | part of a transaction in which the right of possession and use of the
309 | User Product is transferred to the recipient in perpetuity or for a
310 | fixed term (regardless of how the transaction is characterized), the
311 | Corresponding Source conveyed under this section must be accompanied
312 | by the Installation Information. But this requirement does not apply
313 | if neither you nor any third party retains the ability to install
314 | modified object code on the User Product (for example, the work has
315 | been installed in ROM).
316 |
317 | The requirement to provide Installation Information does not include a
318 | requirement to continue to provide support service, warranty, or updates
319 | for a work that has been modified or installed by the recipient, or for
320 | the User Product in which it has been modified or installed. Access to a
321 | network may be denied when the modification itself materially and
322 | adversely affects the operation of the network or violates the rules and
323 | protocols for communication across the network.
324 |
325 | Corresponding Source conveyed, and Installation Information provided,
326 | in accord with this section must be in a format that is publicly
327 | documented (and with an implementation available to the public in
328 | source code form), and must require no special password or key for
329 | unpacking, reading or copying.
330 |
331 | 7. Additional Terms.
332 |
333 | "Additional permissions" are terms that supplement the terms of this
334 | License by making exceptions from one or more of its conditions.
335 | Additional permissions that are applicable to the entire Program shall
336 | be treated as though they were included in this License, to the extent
337 | that they are valid under applicable law. If additional permissions
338 | apply only to part of the Program, that part may be used separately
339 | under those permissions, but the entire Program remains governed by
340 | this License without regard to the additional permissions.
341 |
342 | When you convey a copy of a covered work, you may at your option
343 | remove any additional permissions from that copy, or from any part of
344 | it. (Additional permissions may be written to require their own
345 | removal in certain cases when you modify the work.) You may place
346 | additional permissions on material, added by you to a covered work,
347 | for which you have or can give appropriate copyright permission.
348 |
349 | Notwithstanding any other provision of this License, for material you
350 | add to a covered work, you may (if authorized by the copyright holders of
351 | that material) supplement the terms of this License with terms:
352 |
353 | a) Disclaiming warranty or limiting liability differently from the
354 | terms of sections 15 and 16 of this License; or
355 |
356 | b) Requiring preservation of specified reasonable legal notices or
357 | author attributions in that material or in the Appropriate Legal
358 | Notices displayed by works containing it; or
359 |
360 | c) Prohibiting misrepresentation of the origin of that material, or
361 | requiring that modified versions of such material be marked in
362 | reasonable ways as different from the original version; or
363 |
364 | d) Limiting the use for publicity purposes of names of licensors or
365 | authors of the material; or
366 |
367 | e) Declining to grant rights under trademark law for use of some
368 | trade names, trademarks, or service marks; or
369 |
370 | f) Requiring indemnification of licensors and authors of that
371 | material by anyone who conveys the material (or modified versions of
372 | it) with contractual assumptions of liability to the recipient, for
373 | any liability that these contractual assumptions directly impose on
374 | those licensors and authors.
375 |
376 | All other non-permissive additional terms are considered "further
377 | restrictions" within the meaning of section 10. If the Program as you
378 | received it, or any part of it, contains a notice stating that it is
379 | governed by this License along with a term that is a further
380 | restriction, you may remove that term. If a license document contains
381 | a further restriction but permits relicensing or conveying under this
382 | License, you may add to a covered work material governed by the terms
383 | of that license document, provided that the further restriction does
384 | not survive such relicensing or conveying.
385 |
386 | If you add terms to a covered work in accord with this section, you
387 | must place, in the relevant source files, a statement of the
388 | additional terms that apply to those files, or a notice indicating
389 | where to find the applicable terms.
390 |
391 | Additional terms, permissive or non-permissive, may be stated in the
392 | form of a separately written license, or stated as exceptions;
393 | the above requirements apply either way.
394 |
395 | 8. Termination.
396 |
397 | You may not propagate or modify a covered work except as expressly
398 | provided under this License. Any attempt otherwise to propagate or
399 | modify it is void, and will automatically terminate your rights under
400 | this License (including any patent licenses granted under the third
401 | paragraph of section 11).
402 |
403 | However, if you cease all violation of this License, then your
404 | license from a particular copyright holder is reinstated (a)
405 | provisionally, unless and until the copyright holder explicitly and
406 | finally terminates your license, and (b) permanently, if the copyright
407 | holder fails to notify you of the violation by some reasonable means
408 | prior to 60 days after the cessation.
409 |
410 | Moreover, your license from a particular copyright holder is
411 | reinstated permanently if the copyright holder notifies you of the
412 | violation by some reasonable means, this is the first time you have
413 | received notice of violation of this License (for any work) from that
414 | copyright holder, and you cure the violation prior to 30 days after
415 | your receipt of the notice.
416 |
417 | Termination of your rights under this section does not terminate the
418 | licenses of parties who have received copies or rights from you under
419 | this License. If your rights have been terminated and not permanently
420 | reinstated, you do not qualify to receive new licenses for the same
421 | material under section 10.
422 |
423 | 9. Acceptance Not Required for Having Copies.
424 |
425 | You are not required to accept this License in order to receive or
426 | run a copy of the Program. Ancillary propagation of a covered work
427 | occurring solely as a consequence of using peer-to-peer transmission
428 | to receive a copy likewise does not require acceptance. However,
429 | nothing other than this License grants you permission to propagate or
430 | modify any covered work. These actions infringe copyright if you do
431 | not accept this License. Therefore, by modifying or propagating a
432 | covered work, you indicate your acceptance of this License to do so.
433 |
434 | 10. Automatic Licensing of Downstream Recipients.
435 |
436 | Each time you convey a covered work, the recipient automatically
437 | receives a license from the original licensors, to run, modify and
438 | propagate that work, subject to this License. You are not responsible
439 | for enforcing compliance by third parties with this License.
440 |
441 | An "entity transaction" is a transaction transferring control of an
442 | organization, or substantially all assets of one, or subdividing an
443 | organization, or merging organizations. If propagation of a covered
444 | work results from an entity transaction, each party to that
445 | transaction who receives a copy of the work also receives whatever
446 | licenses to the work the party's predecessor in interest had or could
447 | give under the previous paragraph, plus a right to possession of the
448 | Corresponding Source of the work from the predecessor in interest, if
449 | the predecessor has it or can get it with reasonable efforts.
450 |
451 | You may not impose any further restrictions on the exercise of the
452 | rights granted or affirmed under this License. For example, you may
453 | not impose a license fee, royalty, or other charge for exercise of
454 | rights granted under this License, and you may not initiate litigation
455 | (including a cross-claim or counterclaim in a lawsuit) alleging that
456 | any patent claim is infringed by making, using, selling, offering for
457 | sale, or importing the Program or any portion of it.
458 |
459 | 11. Patents.
460 |
461 | A "contributor" is a copyright holder who authorizes use under this
462 | License of the Program or a work on which the Program is based. The
463 | work thus licensed is called the contributor's "contributor version".
464 |
465 | A contributor's "essential patent claims" are all patent claims
466 | owned or controlled by the contributor, whether already acquired or
467 | hereafter acquired, that would be infringed by some manner, permitted
468 | by this License, of making, using, or selling its contributor version,
469 | but do not include claims that would be infringed only as a
470 | consequence of further modification of the contributor version. For
471 | purposes of this definition, "control" includes the right to grant
472 | patent sublicenses in a manner consistent with the requirements of
473 | this License.
474 |
475 | Each contributor grants you a non-exclusive, worldwide, royalty-free
476 | patent license under the contributor's essential patent claims, to
477 | make, use, sell, offer for sale, import and otherwise run, modify and
478 | propagate the contents of its contributor version.
479 |
480 | In the following three paragraphs, a "patent license" is any express
481 | agreement or commitment, however denominated, not to enforce a patent
482 | (such as an express permission to practice a patent or covenant not to
483 | sue for patent infringement). To "grant" such a patent license to a
484 | party means to make such an agreement or commitment not to enforce a
485 | patent against the party.
486 |
487 | If you convey a covered work, knowingly relying on a patent license,
488 | and the Corresponding Source of the work is not available for anyone
489 | to copy, free of charge and under the terms of this License, through a
490 | publicly available network server or other readily accessible means,
491 | then you must either (1) cause the Corresponding Source to be so
492 | available, or (2) arrange to deprive yourself of the benefit of the
493 | patent license for this particular work, or (3) arrange, in a manner
494 | consistent with the requirements of this License, to extend the patent
495 | license to downstream recipients. "Knowingly relying" means you have
496 | actual knowledge that, but for the patent license, your conveying the
497 | covered work in a country, or your recipient's use of the covered work
498 | in a country, would infringe one or more identifiable patents in that
499 | country that you have reason to believe are valid.
500 |
501 | If, pursuant to or in connection with a single transaction or
502 | arrangement, you convey, or propagate by procuring conveyance of, a
503 | covered work, and grant a patent license to some of the parties
504 | receiving the covered work authorizing them to use, propagate, modify
505 | or convey a specific copy of the covered work, then the patent license
506 | you grant is automatically extended to all recipients of the covered
507 | work and works based on it.
508 |
509 | A patent license is "discriminatory" if it does not include within
510 | the scope of its coverage, prohibits the exercise of, or is
511 | conditioned on the non-exercise of one or more of the rights that are
512 | specifically granted under this License. You may not convey a covered
513 | work if you are a party to an arrangement with a third party that is
514 | in the business of distributing software, under which you make payment
515 | to the third party based on the extent of your activity of conveying
516 | the work, and under which the third party grants, to any of the
517 | parties who would receive the covered work from you, a discriminatory
518 | patent license (a) in connection with copies of the covered work
519 | conveyed by you (or copies made from those copies), or (b) primarily
520 | for and in connection with specific products or compilations that
521 | contain the covered work, unless you entered into that arrangement,
522 | or that patent license was granted, prior to 28 March 2007.
523 |
524 | Nothing in this License shall be construed as excluding or limiting
525 | any implied license or other defenses to infringement that may
526 | otherwise be available to you under applicable patent law.
527 |
528 | 12. No Surrender of Others' Freedom.
529 |
530 | If conditions are imposed on you (whether by court order, agreement or
531 | otherwise) that contradict the conditions of this License, they do not
532 | excuse you from the conditions of this License. If you cannot convey a
533 | covered work so as to satisfy simultaneously your obligations under this
534 | License and any other pertinent obligations, then as a consequence you may
535 | not convey it at all. For example, if you agree to terms that obligate you
536 | to collect a royalty for further conveying from those to whom you convey
537 | the Program, the only way you could satisfy both those terms and this
538 | License would be to refrain entirely from conveying the Program.
539 |
540 | 13. Remote Network Interaction; Use with the GNU General Public License.
541 |
542 | Notwithstanding any other provision of this License, if you modify the
543 | Program, your modified version must prominently offer all users
544 | interacting with it remotely through a computer network (if your version
545 | supports such interaction) an opportunity to receive the Corresponding
546 | Source of your version by providing access to the Corresponding Source
547 | from a network server at no charge, through some standard or customary
548 | means of facilitating copying of software. This Corresponding Source
549 | shall include the Corresponding Source for any work covered by version 3
550 | of the GNU General Public License that is incorporated pursuant to the
551 | following paragraph.
552 |
553 | Notwithstanding any other provision of this License, you have
554 | permission to link or combine any covered work with a work licensed
555 | under version 3 of the GNU General Public License into a single
556 | combined work, and to convey the resulting work. The terms of this
557 | License will continue to apply to the part which is the covered work,
558 | but the work with which it is combined will remain governed by version
559 | 3 of the GNU General Public License.
560 |
561 | 14. Revised Versions of this License.
562 |
563 | The Free Software Foundation may publish revised and/or new versions of
564 | the GNU Affero General Public License from time to time. Such new versions
565 | will be similar in spirit to the present version, but may differ in detail to
566 | address new problems or concerns.
567 |
568 | Each version is given a distinguishing version number. If the
569 | Program specifies that a certain numbered version of the GNU Affero General
570 | Public License "or any later version" applies to it, you have the
571 | option of following the terms and conditions either of that numbered
572 | version or of any later version published by the Free Software
573 | Foundation. If the Program does not specify a version number of the
574 | GNU Affero General Public License, you may choose any version ever published
575 | by the Free Software Foundation.
576 |
577 | If the Program specifies that a proxy can decide which future
578 | versions of the GNU Affero General Public License can be used, that proxy's
579 | public statement of acceptance of a version permanently authorizes you
580 | to choose that version for the Program.
581 |
582 | Later license versions may give you additional or different
583 | permissions. However, no additional obligations are imposed on any
584 | author or copyright holder as a result of your choosing to follow a
585 | later version.
586 |
587 | 15. Disclaimer of Warranty.
588 |
589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
597 |
598 | 16. Limitation of Liability.
599 |
600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
608 | SUCH DAMAGES.
609 |
610 | 17. Interpretation of Sections 15 and 16.
611 |
612 | If the disclaimer of warranty and limitation of liability provided
613 | above cannot be given local legal effect according to their terms,
614 | reviewing courts shall apply local law that most closely approximates
615 | an absolute waiver of all civil liability in connection with the
616 | Program, unless a warranty or assumption of liability accompanies a
617 | copy of the Program in return for a fee.
618 |
619 | END OF TERMS AND CONDITIONS
620 |
621 | How to Apply These Terms to Your New Programs
622 |
623 | If you develop a new program, and you want it to be of the greatest
624 | possible use to the public, the best way to achieve this is to make it
625 | free software which everyone can redistribute and change under these terms.
626 |
627 | To do so, attach the following notices to the program. It is safest
628 | to attach them to the start of each source file to most effectively
629 | state the exclusion of warranty; and each file should have at least
630 | the "copyright" line and a pointer to where the full notice is found.
631 |
632 |
633 | Copyright (C)
634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published
637 | by the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
662 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NodeScriptKit
2 | NodeScriptKit项目,简称nsk项目。它是
3 | - 一个社区驱动的,命令小抄项目
4 | - 一个可自由扩展配置,支持订阅,交互式的,服务器辅助脚本汇总集合
5 | - 一个能够节省你大量命令/脚本查找时间的项目
6 |
7 | ## 使用方法
8 |
9 | ```
10 | bash <(curl -sL https://sh.nodeseek.com)
11 | ```
12 |
13 | 
14 |
15 | ## 主配置文件说明
16 | - 配置文件采用[toml格式](https://toml.io/cn/v1.0.0),可以使用[vscode](https://code.visualstudio.com/)配合[Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml)插件或者一些[在线编辑器](https://www.toml-lint.com/)编辑
17 | - nsk的主配置文件默认位于/etc/nsk/config.toml
18 | - 常用的配置入口包括[local]和[remote],分别代表本地模块文件和远程订阅文件,本地和远程都可以合并/覆盖配置
19 | - 合并配置toml解析后的对象合并,而非文本拼接
20 | - 本地配置文件支持通配符,对匹配到的文件按文件名[自然排序](https://github.com/facette/natsort)后导入
21 | - 默认`/etc/nsk/modules.d/default/*.toml`为官方模块,更新时会清空内容后再更新
22 | - 默认`/etc/nsk/modules.d/extend/*.toml`为用户模块,更新菜单时不会清空内容
23 | - 支持订阅,多个订阅链接会并发加载
24 |
25 | ## 模块配置文件说明
26 | 模块配置是用户打交道比较多的地方,内容包括脚本和菜单,菜单可以指向子菜单(们)和脚本
27 |
28 | ### 脚本示例
29 | ```
30 | [scripts]
31 | # 脚本集合,键值对
32 | memory = "free -h"
33 | disk = "df -hT"
34 | cpuinfo = "cat /proc/cpuinfo"
35 | whoami = "whoami"
36 |
37 | hello = "echo \"hello world\""
38 | yabs = "curl -sL yabs.sh | bash"
39 | docker = "bash <(curl -sL 'https://get.docker.com')"
40 |
41 | test = "echo '这是一个测试项'"
42 | ```
43 |
44 | 脚本部分比较简单,是一系列键值对,一个键对应一个字符串的值
45 |
46 | ### 菜单示例
47 |
48 | ```
49 | [[menus]]
50 | id = "main"
51 | title = "主菜单"
52 | sub_menus = [
53 | "info",
54 | "tool",
55 | "test"
56 | ]
57 |
58 | [[menus]]
59 | id = "info"
60 | title = "系统信息"
61 | sub_menus = [
62 | "cpu",
63 | "memory",
64 | "disk",
65 | "current-user",
66 | ]
67 |
68 | [[menus]]
69 | id = "test"
70 | title = "测试项"
71 | script = "test"
72 | ```
73 |
74 | 如上面所示,main菜单是入口菜单,有3个子菜单,其中info子菜单有进一步的子菜单,而test菜单没有下级,直接指向id为test的脚本
75 |
76 | 这些菜单id负责穿针引线,落叶归根到脚本id
77 |
78 | ## 扩展/覆盖配置的方式
79 | NodeScriptKit支持合并配置文件且支持订阅远程配置,如果你是在本地调试,可以将新的配置文件放置到/etc/nsk/modules.d/extend/ 目录下,文件扩展名为toml
80 |
81 | 如果分享给其他用户,可以放到GitHub上并分享为raw文件直链,接受分享的用户可以修改/etc/nsk/config.toml中[remote]/subscribes的配置文本
82 | 下面给出一个示例配置,很容易看懂
83 | ```
84 | [scripts]
85 | test1 = "echo test1"
86 |
87 | [[menus]]
88 | id = "main"
89 | title = "主菜单"
90 | sub_menus = [
91 | "my-append", # 给主菜单补充新的入口
92 | ]
93 |
94 | # 新的菜单入口
95 | [[menus]]
96 | id = "my-append"
97 | title = "补充菜单"
98 | sub_menus = [
99 | "test1",
100 | ]
101 |
102 | [[menus]]
103 | id = "test1"
104 | title = "打印 test1"
105 | script = "test1"
106 | ```
107 |
108 | ## 代码提交规范和约定
109 | - 鼓励开发者通过pr贡献内容
110 | - 提交的内容主要包括菜单和脚本,菜单放到modules.d下,脚本放到shell_scripts下
111 | - 菜单类要以3位数字开头,安装优先级排序,数值大的内容可以合并/覆盖数值小的
112 | - 脚本类尽量在文件开头写明代码脚本描述,可以参考这个[模板文件](./shell_scripts/example.v0.0.1.0417.sh)
113 | - 脚本尽量使用交互式调用
114 |
115 | ## 社区公约&开发指南
116 | - [社区公约](./Development.md)
117 | - [开发指南](./Rules.md)
--------------------------------------------------------------------------------
/Rules.md:
--------------------------------------------------------------------------------
1 | ## **一、介绍**
2 |
3 | NodeScriptKit 是一个面向 VPS 和独立服务器用户的开源脚本工具集,旨在通过一键式脚本简化系统管理、网络测试和性能优化。我们致力于为用户提供高效、易用的工具,同时欢迎社区成员共同完善项目。
4 |
5 | 当前,我们正在扩展功能并提升稳定性,需要更多热情的贡献者加入。如果你对 Linux 系统管理、脚本开发或社区建设感兴趣,欢迎成为 NodeScriptKit 的一员!
6 |
7 |
8 | ## **二、承诺**
9 |
10 | 作为 NodeScriptKit 社区的成员、贡献者和负责人,我们致力于为每个人提供一个开放、友好、包容和尊重的工作环境,不论其年龄、性别、种族、国籍、技术水平或其他特征。
11 |
12 | 我们相信,多元化的视角和协作精神是推动项目发展的核心动力。
13 |
14 | 为了实现这一目标,我们承诺在社区互动中遵循以下原则,并期待所有参与者共同遵守。
15 |
16 |
17 | ## **三、行为准则**
18 |
19 |
20 | ### **期待的行为**
21 |
22 | 我们鼓励以下行为,以营造积极的社区氛围:
23 |
24 |
25 |
26 | * **尊重与包容**:尊重他人的意见、经验和贡献,即使存在分歧。
27 | * **协作精神**:积极分享知识,协助他人解决问题。
28 | * **建设性反馈**:提供清晰、有帮助的建议,推动项目改进。
29 | * **友善沟通**:使用礼貌和鼓励的语言,避免攻击性或贬低性言辞。
30 | * **责任感**:对自己的贡献负责,确保代码和文档的质量。
31 |
32 |
33 | ### **不可接受的行为**
34 |
35 | 以下行为在 NodeScriptKit 社区中是不被容忍的:
36 |
37 |
38 |
39 | * **骚扰与歧视**:针对个人或群体的辱骂、威胁、歧视性言论或任何形式的骚扰。
40 | * **恶意行为**:故意提交破坏性代码、散布虚假信息或干扰社区运作。
41 | * **人身攻击**:针对他人的外貌、能力或身份进行负面评论。
42 | * **不当内容**:发布色情、暴力或其他不适当的内容。
43 | * **违反隐私**:未经同意泄露他人的个人信息。
44 |
45 |
46 | ## **四、贡献规范**
47 |
48 |
49 | ### **如何参与**
50 |
51 |
52 |
53 | * **代码贡献**:通过 Pull Request 提交代码,遵循 中的规范。
54 | * **问题反馈**:在 Issue 页面报告 Bug 或提出建议,提供详细描述。
55 | * **文档完善**:改进使用说明、翻译内容或补充示例。
56 | * **社区讨论**:通过指定的沟通渠道(如 nodeseek 指定的帖子)参与交流。
57 |
58 |
59 | ### **审核与合并**
60 |
61 |
62 |
63 | * 所有贡献将由维护者审核,确保符合项目目标和技术标准。
64 | * 我们鼓励贡献者在提交前自测代码,并附上必要的说明。
65 |
66 |
67 | ## **五、执行与监督**
68 |
69 |
70 | ### **报告问题**
71 |
72 | 如果您发现任何违反公约的行为,请通过以下方式报告:
73 |
74 | * **GitHub**:在仓库的 Issue 页面提交(可匿名)。
75 | * 请提供具体细节(如时间、事件描述、相关链接),以便我们调查。
76 |
77 |
78 | ### **处理流程**
79 |
80 |
81 |
82 | * **调查**:维护团队将对报告进行保密审查,必要时联系相关方。
83 | * **措施**:根据情况采取警告、临时禁言或永久移除等措施。
84 | * **透明性**:在不泄露隐私的前提下,公布处理结果。
85 |
86 |
87 | ### **后果**
88 |
89 | 违反公约者可能面临以下后果:
90 |
91 |
92 |
93 | * 删除不当内容。
94 | * 暂停或禁止参与社区。
95 | * 在严重情况下,报告给相关平台(如 GitHub )。
96 |
97 |
98 | ## **六、适用范围**
99 |
100 | 本公约适用于所有与 NodeScriptKit 项目相关的活动,包括但不限于:
101 |
102 |
103 |
104 | * GitHub 仓库(Issue、PR、Discussions 等)。
105 | * 社区沟通渠道(如 Telegram、Nodeseek)。
106 | * 项目相关的线上活动。
107 |
108 |
109 | ## **七、致谢**
110 |
111 | 本公约参考了[ Contributor Covenant](https://www.contributor-covenant.org/),并根据 NodeScriptKit 社区的实际情况进行了调整。
112 |
113 | 感谢所有为社区建设贡献力量的成员!
114 |
115 | 参与的小伙伴,会将您的贡献,书写在感谢榜中保存,用以感谢您的贡献。
116 |
117 |
118 | 让我们共同努力,打造一个卓越的 NodeScriptKit 社区!
119 |
--------------------------------------------------------------------------------
/img/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/c445320454ad2fc6094f1b885cb189daa917bbef/img/screenshot1.png
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # 功能: NodeScriptKit 安装和更新脚本
3 |
4 | goos=$(uname -s | tr '[:upper:]' '[:lower:]')
5 | goarch=$(uname -m)
6 |
7 | echo "Current OS: $goos"
8 | echo "Current Architecture: $goarch"
9 |
10 | if [ "$goos" == "darwin" ]; then
11 | ext=""
12 | elif [ "$goos" == "linux" ] || [ "$goos" == "freebsd" ]; then
13 | ext=""
14 | else
15 | echo "Unsupported OS: $goos"
16 | exit 1
17 | fi
18 |
19 | if [ "$goarch" == "x86_64" ]; then
20 | arch="amd64"
21 | elif [ "$goarch" == "i386" ]; then
22 | arch="386"
23 | elif [ "$goarch" == "arm64" ]; then
24 | arch="arm64"
25 | else
26 | echo "Unsupported Architecture: $goarch"
27 | exit 1
28 | fi
29 |
30 | BIN_VERSION="$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/NodeSeekDev/NskCore/releases/latest)"
31 | BIN_VERSION=${BIN_VERSION##*/}
32 | BIN_FILENAME="nskCore-$goos-$arch$ext"
33 | BIN_URL="https://github.com/NodeSeekDev/NskCore/releases/download/$BIN_VERSION/$BIN_FILENAME"
34 |
35 | curl -Lso /usr/bin/nskCore $BIN_URL
36 | chmod u+x /usr/bin/nskCore
37 |
38 | if tar --version 2>&1 | grep -qi 'busybox'; then
39 | if command -v apk >/dev/null 2>&1; then
40 | apk add --no-cache tar
41 | fi
42 | fi
43 |
44 | MENU_URL="$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/NodeSeekDev/NodeScriptKit/releases/latest)"
45 | MENU_VERSION="${MENU_URL##*/}"
46 |
47 | mkdir -p /etc/nsk/modules.d/default
48 | mkdir -p /etc/nsk/modules.d/extend
49 |
50 | cd /tmp
51 | temp_dir=$(mktemp -d)
52 | curl -sLo - $temp_download_file "https://github.com/NodeSeekDev/NodeScriptKit/archive/refs/tags/$MENU_VERSION.tar.gz" | \
53 | tar -xzv -C $temp_dir
54 | [ -f "/etc/nsk/config.toml" ] || cp $temp_dir/*/menu.toml /etc/nsk/config.toml
55 | rm -rf /etc/nsk/modules.d/default/* # Remove old scripts to prevent conflicts
56 | cp $temp_dir/*/modules.d/* /etc/nsk/modules.d/default/
57 |
58 | echo $MENU_VERSION > /etc/nsk/version
59 |
60 | cp $temp_dir/*/nsk.sh /usr/bin/nsk
61 | chmod u+x /usr/bin/nsk
62 | [ -f "/usr/bin/n" ] || ln -s /usr/bin/nsk /usr/bin/n
63 |
64 | rm -rf $temp_dir
65 |
66 | echo -e "\e[1;32mnsk脚本安装成功啦,可以输入n或者nsk命令唤出菜单\e[0m"
67 |
--------------------------------------------------------------------------------
/menu.toml:
--------------------------------------------------------------------------------
1 | [app]
2 |
3 | title = "NodeScriptKit - 脚本工具集合"
4 | splash = """
5 |
6 | ███╗ ██╗ ██████╗ ██████╗ ███████╗███████╗ ██████╗██████╗ ██╗██████╗ ████████╗██╗ ██╗██╗████████╗
7 | ████╗ ██║██╔═══██╗██╔══██╗██╔════╝██╔════╝██╔════╝██╔══██╗██║██╔══██╗╚══██╔══╝██║ ██╔╝██║╚══██╔══╝
8 | ██╔██╗ ██║██║ ██║██║ ██║█████╗ ███████╗██║ ██████╔╝██║██████╔╝ ██║ █████╔╝ ██║ ██║
9 | ██║╚██╗██║██║ ██║██║ ██║██╔══╝ ╚════██║██║ ██╔══██╗██║██╔═══╝ ██║ ██╔═██╗ ██║ ██║
10 | ██║ ╚████║╚██████╔╝██████╔╝███████╗███████║╚██████╗██║ ██║██║██║ ██║ ██║ ██╗██║ ██║
11 | ╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝
12 |
13 | """
14 | splash_timeout = 500 # ms
15 | entry = 'main'
16 |
17 | [local]
18 | include = [
19 | '/etc/nsk/modules.d/default/*.toml',
20 | '/etc/nsk/modules.d/extend/*.toml',
21 | ]
22 |
23 | [remote]
24 | subscribes = [
25 | # remote urls
26 | ]
27 |
--------------------------------------------------------------------------------
/modules.d/000-menu.toml:
--------------------------------------------------------------------------------
1 | [[menus]]
2 | id = "main"
3 | title = "主菜单"
4 | sub_menus = [
5 | "system_info", #系统信息
6 | "test_tool", #测试工具
7 | "system_reinstall", #重装系统
8 | "system_manage", #系统管理
9 | "network_tools", #网络工具
10 | "security_tools", #安全工具
11 | "app_deployment", #应用部署
12 | "utility_tools", #其他实用工具
13 | ]
--------------------------------------------------------------------------------
/modules.d/010-system_info.toml:
--------------------------------------------------------------------------------
1 | [scripts]
2 | # 脚本集合,键值对
3 | memory = "free -h"
4 | disk = "df -hT"
5 | cpuinfo = "cat /proc/cpuinfo"
6 | whoami = "whoami"
7 |
8 | hello = "echo \"hello world\""
9 | docker = "bash <(curl -sL 'https://get.docker.com')"
10 |
11 | test = "echo '这是一个测试项'"
12 |
13 | dir_size_stat = "read -p \"请输入要统计的目录(回车为当前目录):\" path; [ -z \"$path\" ] && path=\".\"; du -BG --max-depth=1 \"$path\" | awk '$1+0>=1 {print}' | sort -hr"
14 | tcp_conn_total = "tcp_conn_num=$(ss -ant | grep ESTAB | wc -l); echo \"当前TCP已建立连接数:$tcp_conn_num\""
15 | tcp_http_total = "tcp_80443_num=$(ss -ant '( sport = :80 or sport = :443 )' | grep ESTAB | wc -l); echo \"80/443端口TCP已建立连接数:$tcp_80443_num\""
16 | top_10_cpu = "top10cpu=$(ps -eo pid,comm,%cpu --sort=-%cpu | head -n 11); echo -e \"Top10耗CPU进程:\n$top10cpu\""
17 |
18 |
19 | [[menus]]
20 | id = "system_info"
21 | title = "系统信息"
22 | sub_menus = [
23 | "cpu",
24 | "memory",
25 | "disk",
26 | "dir_size_stat",
27 | "tcp_conn_total",
28 | "tcp_http_total",
29 | "top_10_cpu",
30 | "current-user",
31 | ]
32 |
33 | [[menus]]
34 | id = "cpu"
35 | title = "查看CPU信息"
36 | script = "cpuinfo"
37 |
38 | [[menus]]
39 | id = "memory"
40 | title = "查看内存信息"
41 | script = "memory"
42 |
43 | [[menus]]
44 | id = "disk"
45 | title = "查看硬盘信息"
46 | script = "disk"
47 |
48 | [[menus]]
49 | id = "dir_size_stat"
50 | title = "查看当前目录大小"
51 | script = "dir_size_stat"
52 |
53 | [[menus]]
54 | id = "tcp_conn_total"
55 | title = "当前TCP连接数"
56 | script = "tcp_conn_total"
57 |
58 | [[menus]]
59 | id = "tcp_http_total"
60 | title = "当前HTTP(s)连接数"
61 | script = "tcp_http_total"
62 |
63 | [[menus]]
64 | id = "top_10_cpu"
65 | title = "top 10 大耗 CPU 进程"
66 | script = "top_10_cpu"
67 |
68 |
69 | [[menus]]
70 | id = "current-user"
71 | title = "查看当前用户"
72 | script = "whoami"
--------------------------------------------------------------------------------
/modules.d/020-test_tool.toml:
--------------------------------------------------------------------------------
1 | [scripts]
2 | #测试类脚本
3 | #NodeQuality
4 | node_quality = "bash <(curl -sL run.NodeQuality.com)"
5 | #融合怪测试
6 | fusion_test = "bash <(curl -sL bash.spiritlhl.net/ecs)"
7 | #IP质量
8 | ip_quality = "bash <(curl -sL Check.Place) -I" #IP质量,交互界面
9 |
10 | network_quality = "bash <(curl -sL Check.Place) -N" #网络质量,交互界面
11 | yabs = "bash <(curl -sL yabs.sh)" #yabs
12 | bench = "bash <(curl -sL bench.sh)" #benchmark
13 | super_bench = "bash <(curl -sL git.io/superbench.sh)" #superbench
14 | super_trace = "bash <(curl -sL raw.githubusercontent.com/oooldking/script/master/supertrace.sh)" #supertrace
15 | unlock_test = "bash <(curl -sL Media.Check.Place)" #解锁检测
16 | return_route = "bash <(curl -sL raw.githubusercontent.com/zhanghanyun/backtrace/main/install.sh)" #回程路由
17 | nws_sh = "bash <(curl -sL nws.sh)" #nws
18 |
19 |
20 | #硬件类测试
21 | dedicated_benchmark = "bash <(curl -sL git.io/ceshi)"
22 | disk_write_test = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/hardware_info/disk_test.sh)"
23 | lemon_bench_full="bash <(curl -sL raw.githubusercontent.com/LemonBench/LemonBench/main/LemonBench.sh) --full"
24 | lemon_bench_fast="bash <(curl -sL raw.githubusercontent.com/LemonBench/LemonBench/main/LemonBench.sh) --fast"
25 | unix_bench = "bash <(curl -sL github.com/teddysun/across/raw/master/unixbench.sh)"
26 | memory_check = "bash <(curl -sL raw.githubusercontent.com/uselibrary/memoryCheck/main/memoryCheck.sh)"
27 |
28 | [[menus]]
29 | id = "test_tool"
30 | title = "测试工具"
31 | sub_menus = [
32 | "node_quality",
33 | "fusion_test",
34 | "ip_quality",
35 | "network_quality",
36 | "yabs",
37 | "bench",
38 | "super_bench",
39 | "unlock_test",
40 | "return_route",
41 | "super_trace",
42 | "nws_sh",
43 |
44 | 'dedicated_benchmark',
45 | 'lemon_bench_full',
46 | 'lemon_bench_fast',
47 | 'unix_bench',
48 | 'disk_write_test',
49 | 'memory_check',
50 | ]
51 |
52 | [[menus]]
53 | id = "node_quality"
54 | title = "NodeQuality"
55 | script = "node_quality"
56 |
57 | [[menus]]
58 | id = "fusion_test"
59 | title = "融合怪"
60 | script = "fusion_test"
61 |
62 | [[menus]]
63 | id = "ip_quality"
64 | title = "IP质量"
65 | script = "ip_quality"
66 |
67 | [[menus]]
68 | id = "network_quality"
69 | title = "网络质量"
70 | script = "network_quality"
71 |
72 | [[menus]]
73 | id = "yabs"
74 | title = "YABS"
75 | script = "yabs"
76 |
77 | [[menus]]
78 | id = "bench"
79 | title = "Bench"
80 | script = "bench"
81 |
82 | [[menus]]
83 | id = "super_bench"
84 | title = "Super Bench"
85 | script = "super_bench"
86 |
87 | [[menus]]
88 | id = "unlock_test"
89 | title = "解锁检测"
90 | script = "unlock_test"
91 |
92 | [[menus]]
93 | id = "return_route"
94 | title = "回程路由[结果版]"
95 | script = "return_route"
96 |
97 | [[menus]]
98 | id = "super_trace"
99 | title = "回程路由[节点版]"
100 | script = "super_trace"
101 |
102 | [[menus]]
103 | id = "nws_sh"
104 | title = "综合测速"
105 | script = "nws_sh"
106 |
107 | [[menus]]
108 | id = "dedicated_benchmark"
109 | title = "独服基准脚本"
110 | script = "dedicated_benchmark"
111 |
112 | [[menus]]
113 | id = "disk_write_test"
114 | title = "硬盘写入测试"
115 | script = "disk_write_test"
116 |
117 | [[menus]]
118 | id = "memory_check"
119 | title = "超售测试"
120 | script = "memory_check"
121 |
122 |
123 | [[menus]]
124 | id = "lemon_bench_full"
125 | title = "LemonBench[完整版]"
126 | script = "lemon_bench_full"
127 |
128 | [[menus]]
129 | id = "lemon_bench_fast"
130 | title = "LemonBench[快速版]"
131 | script = "lemon_bench_fast"
132 |
133 | [[menus]]
134 | id = "unix_bench"
135 | title = "UnixBench"
136 | script = "unix_bench"
137 |
--------------------------------------------------------------------------------
/modules.d/030-system_reinstall.toml:
--------------------------------------------------------------------------------
1 | [scripts]
2 | #重装系统
3 | reinstall = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/system_reinstall/reinstall.sh)"
4 | installnet = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/system_reinstall/installnet.sh)"
5 | osmutation = "bash <(curl -sL raw.githubusercontent.com/LloydAsp/OsMutation/main/OsMutation.sh)"
6 |
7 | [[menus]]
8 | id = "system_reinstall"
9 | title = "重装系统"
10 | sub_menus = [
11 | "reinstall",
12 | "installnet",
13 | "osmutation",
14 | ]
15 |
16 | #重装系统
17 | [[menus]]
18 | id = "reinstall"
19 | title = "Reinstall"
20 | script = "reinstall"
21 |
22 | [[menus]]
23 | id = "installnet"
24 | title = "InstallNET.sh"
25 | script = "installnet"
26 |
27 | [[menus]]
28 | id = "osmutation"
29 | title = "OsMutation"
30 | script = "osmutation"
--------------------------------------------------------------------------------
/modules.d/040-system_manage.toml:
--------------------------------------------------------------------------------
1 | [scripts]
2 | #系统管理
3 | kernel_network_optimizer = "bash <(curl -Lso- git.io/kernel.sh)"
4 | dns_unlock = "bash <(curl -sL raw.githubusercontent.com/Jimmyzxk/DNS-Alice-Unlock/refs/heads/main/dns-unlock.sh)"
5 | add_zram = "bash <(curl -sL raw.githubusercontent.com/spiritLHLS/addzram/main/addzram.sh)"
6 | add_swap = "bash <(curl -sL raw.githubusercontent.com/spiritLHLS/addswap/main/addswap.sh)"
7 |
8 | manage_services = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/system_manage/manage_services.sh)"
9 | terminal_setup = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/system_manage/terminal_setup.sh)"
10 |
11 | [[menus]]
12 | id = "system_manage"
13 | title = "系统管理"
14 | sub_menus = [
15 | 'manage_services',
16 | 'kernel_network_optimizer',
17 | 'dns_unlock',
18 | 'add_zram',
19 | 'add_swap',
20 | 'terminal_setup',
21 | ]
22 |
23 | [[menus]]
24 | id = "manage_services"
25 | title = "系统&用户服务管理"
26 | script = "manage_services"
27 |
28 | [[menus]]
29 | id = "kernel_network_optimizer"
30 | title = "内核与网络优化"
31 | script = "kernel_network_optimizer"
32 |
33 | [[menus]]
34 | id = "dns_unlock"
35 | title = "一键修改解锁DNS"
36 | script = "dns_unlock"
37 |
38 | [[menus]]
39 | id = "add_zram"
40 | title = "addZram"
41 | script = "add_zram"
42 |
43 | [[menus]]
44 | id = "add_swap"
45 | title = "addSwap"
46 | script = "add_swap"
47 |
48 | [[menus]]
49 | id = "terminal_setup"
50 | title = "Terminal美化&优化历史记录"
51 | script = "terminal_setup"
--------------------------------------------------------------------------------
/modules.d/060-network_tools.toml:
--------------------------------------------------------------------------------
1 | [scripts]
2 | #网络工具
3 | bbr_install = "bash <(curl -sL sh.nekoneko.cloud/bbr/bbr.sh)"
4 | bbr_tcpx_install = "bash <(curl -sL raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcpx.sh)"
5 | app_warp = "bash <(curl -sL gitlab.com/fscarmen/warp_unlock/-/raw/main/unlock.sh)"
6 | brook_pf_install = "bash <(curl -Lso- sh.nekoneko.cloud/brook-pf/brook-pf.sh)"
7 | tools_install = "bash <(curl -Lso- raw.githubusercontent.com/BlackSheep-cry/TCP-Optimization-Tool/main/tool.sh)"
8 | realm_install = "bash <(curl -Lso- raw.githubusercontent.com/qqrrooty/EZrealm/main/realm.sh)"
9 | gost_install = "bash <(curl -Lso- raw.githubusercontent.com/qqrrooty/EZgost/main/gost.sh)"
10 |
11 |
12 | [[menus]]
13 | id = "network_tools"
14 | title = "网络工具"
15 | sub_menus = [
16 | 'tools_install',
17 | 'bbr_install',
18 | 'app_warp',
19 | 'bbr_tcpx_install',
20 | 'realm_install',
21 | 'gost_install',
22 | 'brook_pf_install',
23 | ]
24 |
25 | [[menus]]
26 | id = "bbr_install"
27 | title = "BBR安装[by Nekoneko]"
28 | script = "bbr_install"
29 |
30 | [[menus]]
31 | id = "bbr_tcpx_install"
32 | title = "锐速/BBRPLUS/BBR2安装[by ylx]"
33 | script = "bbr_tcpx_install"
34 |
35 | [[menus]]
36 | id = "app_warp"
37 | title = "warp安装"
38 | script = "app_warp"
39 |
40 | [[menus]]
41 | id = "tools_install"
42 | title = "TCP调优"
43 | script = "tools_install"
44 |
45 | [[menus]]
46 | id = "realm_install"
47 | title = "Realm 一键转发"
48 | script = "realm_install"
49 |
50 | [[menus]]
51 | id = "gost_install"
52 | title = "Ghost 一键转发"
53 | script = "gost_install"
54 |
55 | [[menus]]
56 | id = "brook_pf_install"
57 | title = "Brook一键转发[by Nekoneko]"
58 | script = "brook_pf_install"
--------------------------------------------------------------------------------
/modules.d/070-security_tools.toml:
--------------------------------------------------------------------------------
1 | [scripts]
2 | #安全工具
3 | fail2ban = "bash <(curl -sL raw.githubusercontent.com/FunctionClub/Fail2ban/master/fail2ban.sh)"
4 |
5 |
6 | [[menus]]
7 | id = "security_tools"
8 | title = "安全工具"
9 | sub_menus = [
10 | 'fail2ban'
11 | ]
12 |
13 | [[menus]]
14 | id = "fail2ban"
15 | title = "Fail2ban"
16 | script = "fail2ban"
17 |
--------------------------------------------------------------------------------
/modules.d/080-app_deployment.toml:
--------------------------------------------------------------------------------
1 | [scripts]
2 | #应用部署
3 | app_bt = "bash <(curl -sL download.bt.cn/install/install_panel.sh) ed8484bec"
4 | app_aapanel = "bash <(curl -sL www.aapanel.com/script/install_7.0_en.sh)"
5 | app_1panel = "bash <(curl -sL resource.1panel.pro/quick_start.sh)"
6 | app_nezha = "bash <(curl -sL raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh)"
7 | app_aria2 = "bash <(curl -sL raw.githubusercontent.com/ToyoDAdoubiBackup/doubi/master/aria2.sh)"
8 | app_alist = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/master/shell_scripts/app_deployment/alist_manager.sh)"
9 | app_aurora = "bash <(curl -sL raw.githubusercontent.com/Aurora-Admin-Panel/deploy/main/install.sh)"
10 |
11 |
12 | [[menus]]
13 | id = "app_deployment"
14 | title = "应用部署"
15 | sub_menus = [
16 | 'app_bt',
17 | 'app_aapanel',
18 | 'app_1panel',
19 | 'app_nezha',
20 | 'app_warp',
21 | 'app_alist',
22 | 'app_aria2',
23 | 'app_aurora',
24 | ]
25 |
26 | [[menus]]
27 | id = "app_bt"
28 | title = "宝塔面板[官方版]"
29 | script = "app_bt"
30 |
31 | [[menus]]
32 | id = "app_aapanel"
33 | title = "Aapanel面板[官方版]"
34 | script = "app_aapanel"
35 |
36 | [[menus]]
37 | id = "app_1panel"
38 | title = "1Panel面板[官方版]"
39 | script = "app_1panel"
40 |
41 | [[menus]]
42 | id = "app_nezha"
43 | title = "nezha面板[官方版]"
44 | script = "app_nezha"
45 |
46 | [[menus]]
47 | id = "app_aria2"
48 | title = "aria2下载器"
49 | script = "app_aria2"
50 |
51 | [[menus]]
52 | id = "app_alist"
53 | title = "alist网盘"
54 | script = "app_alist"
55 |
56 | [[menus]]
57 | id = "app_aurora"
58 | title = "极光面板"
59 | script = "app_aurora"
--------------------------------------------------------------------------------
/modules.d/090-utility_tools.toml:
--------------------------------------------------------------------------------
1 | [scripts]
2 | # 脚本集合,键值对
3 | ssh_management = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/utility_tools/ssh_management.sh)"
4 | crontab_management = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/utility_tools/crontab_management.sh)"
5 | hostname_management = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/utility_tools/hostname_management.sh)"
6 | ports_management = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/utility_tools/ports_management.sh)"
7 | auto_mount_disk = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/utility_tools/auto_mount_disk.sh)"
8 | geek_prompt = "bash <(curl -sL raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/shell_scripts/utility_tools/geek_prompt.sh)"
9 |
10 | [[menus]]
11 | id = "utility_tools"
12 | title = "实用工具"
13 | sub_menus = [
14 | 'ssh_management',
15 | 'crontab_management',
16 | 'ports_management',
17 | 'hostname_management',
18 | 'auto_mount_disk',
19 | 'geek_prompt',
20 | ]
21 |
22 | [[menus]]
23 | id = "ssh_management"
24 | title = "SSH 管理"
25 | script = "ssh_management"
26 |
27 | [[menus]]
28 | id = "crontab_management"
29 | title = "Crontab 管理"
30 | script = "crontab_management"
31 |
32 | [[menus]]
33 | id = "ports_management"
34 | title = "端口管理"
35 | script = "ports_management"
36 |
37 | [[menus]]
38 | id = "hostname_management"
39 | title = "修改主机名称"
40 | script = "hostname_management"
41 |
42 | [[menus]]
43 | id = "auto_mount_disk"
44 | title = "挂载磁盘管理"
45 | script = "auto_mount_disk"
46 |
47 | [[menus]]
48 | id = "geek_prompt"
49 | title = "Geek Prompt 美化终端"
50 | script = "geek_prompt"
51 |
--------------------------------------------------------------------------------
/nsk.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | MENU_URL="$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/NodeSeekDev/NodeScriptKit/releases/latest)"
3 | MENU_VERSION="${MENU_URL##*/}"
4 | if [ -n "$MENU_VERSION" ] && \
5 | [ "$MENU_VERSION" != latest ] && \
6 | [ "$MENU_VERSION" != "$(cat /etc/nsk/version)" ] ; then
7 | echo "检测到有新版本可以更新,是否升级?[y/N]"
8 | read -r ans
9 | if [ "$ans" = "y" ] || [ "$ans" = "Y" ]; then
10 | bash <(curl -Ls https://raw.githubusercontent.com/NodeSeekDev/NodeScriptKit/refs/heads/main/install.sh) && exit
11 | else
12 | echo "已取消升级"
13 | fi
14 | fi
15 | nskCore -config /etc/nsk/config.toml
16 |
--------------------------------------------------------------------------------
/shell_scripts/app_deployment/alist_manager.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: disk_test.sh
5 | # 功能: 这是一个 AList 安装与管理脚本,用于安装、更新、卸载 AList 或显示其管理菜单。
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-13
8 |
9 | ### === 版本信息 === ###
10 | SCRIPT_VERSION="0.0.1"
11 | echo -e "\033[32m[信息] 脚本版本: $SCRIPT_VERSION\033[0m"
12 |
13 | ### === 退出状态码 === ###
14 | EXIT_SUCCESS=0
15 | EXIT_ERROR=1
16 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
17 |
18 | ### === 权限检查 === ###
19 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
20 |
21 | ### === 颜色定义 === ###
22 | RED='\033[0;31m'
23 | GREEN='\033[0;32m'
24 | YELLOW='\033[0;33m'
25 | CYAN='\033[0;36m'
26 | BLUE='\033[34m';
27 | NC='\033[0m'
28 |
29 | ### === 彩色输出函数 === ###
30 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
31 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
32 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
33 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
34 |
35 | ### === 信号捕获 === ###
36 | cleanup() {
37 | log "INFO" "脚本被中断..."
38 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
39 | exit $EXIT_INTERRUPT
40 | }
41 | trap cleanup SIGINT SIGTERM
42 |
43 | ### === 逻辑正式开始 === ###
44 |
45 | # Install dependencies
46 | install_dependencies() {
47 | local sys_id=$(cat /etc/os-release | grep ^ID= | cut -d'=' -f2 | tr -d '"')
48 | local pkg="curl"
49 | info "检查并安装依赖: $pkg..."
50 | command -v "$pkg" &>/dev/null && { success "$pkg 已安装"; return 0; }
51 | case $sys_id in
52 | centos|rhel|fedora|rocky|almalinux)
53 | command -v dnf &>/dev/null && dnf install -y "$pkg" &>/dev/null || yum install -y "$pkg" &>/dev/null
54 | ;;
55 | debian|ubuntu|linuxmint)
56 | apt update -y &>/dev/null && apt install -y "$pkg" &>/dev/null
57 | ;;
58 | arch|manjaro)
59 | pacman -Syu --noconfirm "$pkg" &>/dev/null
60 | ;;
61 | opensuse|suse)
62 | zypper install -y "$pkg" &>/dev/null
63 | ;;
64 | alpine)
65 | apk add "$pkg" &>/dev/null
66 | ;;
67 | openwrt)
68 | opkg install "$pkg" &>/dev/null
69 | ;;
70 | *)
71 | danger "未知系统: $sys_id,请手动安装 $pkg"
72 | exit 1
73 | ;;
74 | esac
75 | command -v "$pkg" &>/dev/null || { danger "无法安装 $pkg"; exit 1; }
76 | success "$pkg 已安装"
77 | }
78 |
79 | # Validate installation path
80 | validate_install_path() {
81 | local path=$1
82 | [[ -z "$path" ]] && path="/opt/alist"
83 | [[ "$path" == /* ]] || { danger "安装路径必须为绝对路径"; return 1; }
84 | echo "$path"
85 | }
86 |
87 | # Execute AList command
88 | execute_alist_command() {
89 | local cmd=$1
90 | info "正在执行命令: $cmd"
91 | bash -c "$cmd"
92 | [[ $? -eq 0 ]] && { success "命令执行成功"; return 0; }
93 | danger "命令执行失败,请检查输出"
94 | return 1
95 | }
96 |
97 | # Main menu for AList management
98 | alist_management() {
99 | check_root
100 | install_dependencies
101 | info "欢迎使用 AList 安装与管理脚本!"
102 | local action=""
103 | local options=("install" "update" "uninstall" "menu")
104 |
105 | while true; do
106 | info "请选择操作:"
107 | select action in "${options[@]}"; do
108 | case "$action" in
109 | install|update|uninstall|menu)
110 | break
111 | ;;
112 | *)
113 | danger "无效选择,请重试"
114 | continue
115 | ;;
116 | esac
117 | done
118 | [[ -n "$action" ]] && break
119 | done
120 |
121 | local cmd=""
122 | case "$action" in
123 | install)
124 | read -p "请输入安装路径(默认 /opt/alist): " install_path
125 | install_path=$(validate_install_path "$install_path") || exit 1
126 | cmd="bash <(curl -sL https://alist.nn.ci/v3.sh) install $install_path"
127 | ;;
128 | update)
129 | cmd="bash <(curl -sL https://alist.nn.ci/v3.sh) update"
130 | ;;
131 | uninstall)
132 | cmd="bash <(curl -sL https://alist.nn.ci/v3.sh) uninstall"
133 | ;;
134 | menu)
135 | cmd="bash <(curl -sL https://alist.nn.ci/v3.sh)"
136 | ;;
137 | esac
138 |
139 | info "即将执行命令: $cmd"
140 | read -p "确认执行?(y/n): " confirm
141 | if [[ "$confirm" =~ ^[Yy]$ ]]; then
142 | execute_alist_command "$cmd" || exit 1
143 | else
144 | info "已取消"
145 | exit 0
146 | fi
147 | }
148 |
149 | # Main execution
150 | alist_management
--------------------------------------------------------------------------------
/shell_scripts/example.v0.0.1.0417.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 名称: [请替换为实际脚本名称,例如 管理本机的端口]
5 | # 功能: [请简要描述脚本功能,例如 "用于查看,封禁,管理本机的端口"]
6 | # 作者: [作者名称] <[作者联系方式或主页,例如 https://www.nodeseek.com/space/29457]>
7 | # 创建日期: [创建日期,例如 2025-04-13]
8 | # 许可证: [例如 MIT, GPL 等,默认 MIT]
9 |
10 |
11 | ### === 版本信息 === ###
12 | SCRIPT_VERSION="0.0.1"
13 | SCRIPT_NAME="[请替换为脚本名称]" #如 管理本机的端口
14 | SCRIPT_AUTHOR="[@作者名称] <作者联系方式或主页,例如 https://www.nodeseek.com/space/29457>"
15 | #e.g
16 | #SCRIPT_AUTHOR="[@Rouxyang] "
17 |
18 | echo -e "\033[33m[信息] $SCRIPT_NAME ,版本: $SCRIPT_VERSION\033[0m"
19 | echo -e "\033[33m[作者] $SCRIPT_AUTHOR\033[0m"
20 |
21 | ### === 权限检查 === ###
22 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
23 |
24 | ### === 依赖检查 === ###
25 | # 检查必要命令是否可用
26 | check_dependencies() {
27 | local deps=("awk" "sed" "grep") # 根据需要修改依赖
28 | for cmd in "${deps[@]}"; do
29 | if ! command -v "$cmd" &>/dev/null; then
30 | danger "缺少必要命令: $cmd"
31 | exit $EXIT_ERROR
32 | fi
33 | done
34 | }
35 |
36 |
37 | ### === 退出状态码 === ###
38 | EXIT_SUCCESS=0
39 | EXIT_ERROR=1
40 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
41 |
42 | ### === 颜色定义 === ###
43 | RED='\033[0;31m'
44 | GREEN='\033[0;32m'
45 | YELLOW='\033[0;33m'
46 | CYAN='\033[0;36m'
47 | NC='\033[0m' # No Color
48 |
49 | ### === 彩色输出函数 === ###
50 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
51 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
52 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
53 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
54 |
55 | ### === 日志记录函数 === ###
56 | # 日志文件路径(可选,默认输出到 stdout)
57 | LOG_FILE="/var/log/${SCRIPT_NAME:-$(basename "${0:-unknown.sh}")}.log"
58 | log() {
59 | local level="$1"
60 | local message="$2"
61 | local timestamp
62 | timestamp=$(date '+%Y-%m-%d %H:%M:%S')
63 | echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE" 2>/dev/null
64 | }
65 |
66 | ### === 信号捕获 === ###
67 | cleanup() {
68 | log "INFO" "脚本被中断..."
69 | warn "[警告] 脚本已退出!"
70 | exit $EXIT_INTERRUPT
71 | }
72 | trap cleanup SIGINT SIGTERM
73 |
74 |
75 | ### === 主函数 === ###
76 | main() {
77 | # 初始化日志
78 | log "INFO" "脚本 $SCRIPT_NAME (版本: $SCRIPT_VERSION) 开始执行"
79 |
80 | # 检查依赖
81 | check_dependencies
82 |
83 | # 脚本核心逻辑(请在此添加具体功能)
84 | info "开始执行脚本逻辑..."
85 |
86 | info "核心逻辑放在这里执行,建议是采用函数式执行调用"
87 |
88 | # 示例逻辑
89 | success "脚本执行完成!"
90 | log "INFO" "脚本执行成功"
91 |
92 | exit $EXIT_SUCCESS
93 | }
94 |
95 | ### === 脚本入口 === ###
96 | main
--------------------------------------------------------------------------------
/shell_scripts/hardware_info/disk_test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: disk_test.sh
5 | # 功能: 这是一个磁盘测试脚本,用于下载、运行 Hard Disk Sentinel 并测试磁盘写入量,完成后清理
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-13
8 |
9 | ### === 版本信息 === ###
10 | SCRIPT_VERSION="0.0.1"
11 | echo -e "\033[32m[信息] 脚本版本: $SCRIPT_VERSION\033[0m"
12 |
13 | ### === 退出状态码 === ###
14 | EXIT_SUCCESS=0
15 | EXIT_ERROR=1
16 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
17 |
18 | ### === 权限检查 === ###
19 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
20 |
21 | ### === 颜色定义 === ###
22 | RED='\033[0;31m'
23 | GREEN='\033[0;32m'
24 | YELLOW='\033[0;33m'
25 | CYAN='\033[0;36m'
26 | BLUE='\033[34m';
27 | NC='\033[0m'
28 |
29 |
30 | ### === 彩色输出函数 === ###
31 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
32 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
33 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
34 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
35 |
36 | ### === 信号捕获 === ###
37 | cleanup() {
38 | log "INFO" "脚本被中断..."
39 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
40 | exit $EXIT_INTERRUPT
41 | }
42 | trap cleanup SIGINT SIGTERM
43 |
44 | ### === 逻辑正式开始 === ###
45 |
46 |
47 | # Install dependencies
48 | install_dependencies() {
49 | local sys_id=$(cat /etc/os-release | grep ^ID= | cut -d'=' -f2 | tr -d '"')
50 | local packages=("wget" "gunzip")
51 | info "检查并安装依赖: ${packages[*]}..."
52 | for pkg in "${packages[@]}"; do
53 | command -v "$pkg" &>/dev/null && continue
54 | case $sys_id in
55 | centos|rhel|fedora|rocky|almalinux)
56 | command -v dnf &>/dev/null && dnf install -y "$pkg" &>/dev/null || yum install -y "$pkg" &>/dev/null
57 | ;;
58 | debian|ubuntu|linuxmint)
59 | apt update -y &>/dev/null && apt install -y "$pkg" &>/dev/null
60 | ;;
61 | arch|manjaro)
62 | pacman -Syu --noconfirm "$pkg" &>/dev/null
63 | ;;
64 | opensuse|suse)
65 | zypper install -y "$pkg" &>/dev/null
66 | ;;
67 | alpine)
68 | apk add "$pkg" &>/dev/null
69 | ;;
70 | openwrt)
71 | opkg install "$pkg" &>/dev/null
72 | ;;
73 | *)
74 | danger "未知系统: $sys_id,请手动安装 $pkg"
75 | exit 1
76 | ;;
77 | esac
78 | command -v "$pkg" &>/dev/null || { danger "无法安装 $pkg"; exit 1; }
79 | done
80 | success "所有依赖已安装"
81 | }
82 |
83 | # Download Hard Disk Sentinel
84 | download_hdsentinel() {
85 | local url="https://www.hdsentinel.com/hdslin/hdsentinel-019c-x64.gz"
86 | local file="hdsentinel-019c-x64.gz"
87 | info "正在下载 Hard Disk Sentinel..."
88 | wget -c "$url" -O "$file" &>/dev/null
89 | [[ $? -eq 0 ]] && { success "下载完成"; return 0; }
90 | danger "下载失败,请检查网络连接或 URL 是否有效"
91 | exit 1
92 | }
93 |
94 | # Extract file
95 | extract_hdsentinel() {
96 | local file="hdsentinel-019c-x64.gz"
97 | info "正在解压 $file..."
98 | gunzip "$file" &>/dev/null
99 | [[ $? -eq 0 ]] && { success "解压完成"; return 0; }
100 | danger "解压失败,请检查文件是否损坏"
101 | exit 1
102 | }
103 |
104 | # Set execute permissions
105 | set_permissions() {
106 | local file="hdsentinel-019c-x64"
107 | info "设置执行权限..."
108 | chmod 755 "$file" &>/dev/null
109 | [[ -x "$file" ]] && { success "权限设置完成"; return 0; }
110 | danger "设置执行权限失败"
111 | exit 1
112 | }
113 |
114 | # Run test
115 | run_test() {
116 | local file="hdsentinel-019c-x64"
117 | info "正在运行 Hard Disk Sentinel 测试..."
118 | ./"$file"
119 | [[ $? -eq 0 ]] && { success "测试完成,结果已输出"; return 0; }
120 | danger "测试执行失败,请检查工具输出"
121 | return 1
122 | }
123 |
124 | # Clean up
125 | cleanup() {
126 | local file="hdsentinel-019c-x64"
127 | info "正在清理测试文件..."
128 | rm -f "$file" &>/dev/null
129 | [[ $? -eq 0 ]] && { success "测试文件已删除"; return 0; }
130 | warn "删除文件失败,请手动清理"
131 | return 1
132 | }
133 |
134 | # Main execution
135 | main() {
136 | install_dependencies
137 | download_hdsentinel
138 | extract_hdsentinel
139 | set_permissions
140 | run_test
141 | cleanup
142 | success "脚本执行完毕"
143 | }
144 |
145 | main
--------------------------------------------------------------------------------
/shell_scripts/system_manage/manage_services.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 名称: manage_services.sh
5 | # 功能: 交互式列举、管理、卸载 systemd 服务;优先显示[用户安装]服务再显示[系统]服务,卸载后生成清单
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-17
8 | # 许可证: MIT
9 |
10 | ### === 版本信息 === ###
11 | SCRIPT_VERSION="1.0.2"
12 | SCRIPT_NAME="manage_services.sh"
13 | SCRIPT_AUTHOR="[你的名称] <你的联系方式或主页>"
14 |
15 | ### === 退出状态码 === ###
16 | EXIT_SUCCESS=0
17 | EXIT_ERROR=1
18 | EXIT_INTERRUPT=130
19 |
20 | ### === 颜色定义 === ###
21 | RED='\033[0;31m'
22 | GREEN='\033[0;32m'
23 | YELLOW='\033[0;33m'
24 | CYAN='\033[0;36m'
25 | NC='\033[0m'
26 |
27 | ### === 彩色输出函数 === ###
28 | success() { printf "${GREEN}%b${NC}\n" "$1"; }
29 | info() { printf "${CYAN}%b${NC}\n" "$1"; }
30 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
31 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
32 |
33 | ### === 日志记录函数 === ###
34 | LOG_FILE="/var/log/${SCRIPT_NAME:-$(basename "${0:-unknown.sh}")}.log"
35 | log() {
36 | local level="$1"
37 | local message="$2"
38 | local timestamp
39 | timestamp=$(date '+%Y-%m-%d %H:%M:%S')
40 | echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE" 2>/dev/null
41 | }
42 |
43 | ### === 权限和依赖检查 === ###
44 | check_systemctl() {
45 | if ! command -v systemctl &>/dev/null; then
46 | danger "未检测到 systemctl,此脚本仅适用于 systemd 系统!"
47 | exit $EXIT_ERROR
48 | fi
49 | }
50 | check_root() {
51 | [[ $EUID -ne 0 ]] && danger "请以root用户或sudo运行此脚本!" && exit $EXIT_ERROR
52 | }
53 | check_dependencies() {
54 | local deps=("awk" "sort")
55 | for cmd in "${deps[@]}"; do
56 | if ! command -v "$cmd" &>/dev/null; then
57 | danger "缺少必要命令: $cmd"
58 | exit $EXIT_ERROR
59 | fi
60 | done
61 | }
62 |
63 | ### === 信号捕获 === ###
64 | cleanup() {
65 | log "INFO" "脚本被中断..."
66 | warn "[警告] 脚本已退出!"
67 | exit $EXIT_INTERRUPT
68 | }
69 | trap cleanup SIGINT SIGTERM
70 |
71 | ### === 生成自查清单函数 === ###
72 | generate_checklist() {
73 | local svc="$1"
74 | local checklist="$HOME/${svc}-uninstall-checklist.txt"
75 |
76 | {
77 | echo "【$svc 残留检查及手工处理建议清单】"
78 | echo
79 |
80 | # 1. systemd unit 文件及自启设置
81 | echo "1. systemd unit 文件及自启设置:"
82 | for p in /etc/systemd/system /usr/lib/systemd/system /lib/systemd/system /usr/local/lib/systemd/system; do
83 | [ -f "$p/${svc}.service" ] && echo " $p/${svc}.service"
84 | done
85 | systemctl_status=$(systemctl is-enabled "$svc" 2>/dev/null)
86 | echo " systemctl is-enabled $svc : $systemctl_status"
87 | systemctl_statustxt=$(systemctl status "$svc" 2>/dev/null | grep -E 'Loaded:|Active:' | sed 's/^/ /')
88 | echo "$systemctl_statustxt"
89 | echo
90 |
91 | # 2. 定时任务自启(crontab)
92 | echo "2. 定时任务自启(crontab):"
93 | found_cron=0
94 | for user in $(cut -d: -f1 /etc/passwd); do
95 | crontab -u "$user" -l 2>/dev/null | grep -i "$svc" && { echo " 用户 $user 的crontab含相关内容"; found_cron=1; }
96 | done
97 | grep -i "$svc" /etc/crontab 2>/dev/null && { echo " /etc/crontab 含相关内容"; found_cron=1; }
98 | for cronf in /etc/cron.d/*; do
99 | grep -i "$svc" "$cronf" 2>/dev/null && { echo " $cronf 含相关内容"; found_cron=1; }
100 | done
101 | [ "$found_cron" = "0" ] && echo " 未发现 crontab 相关条目"
102 | echo
103 |
104 | # 3. rc.local / profile / XDG autostart
105 | echo "3. rc.local / profile / XDG autostart 相关自启:"
106 | for pf in /etc/rc.local /etc/profile /etc/bashrc /home/*/.bashrc /home/*/.profile /home/*/.bash_profile; do
107 | grep -i "$svc" "$pf" 2>/dev/null && echo " $pf 含相关内容"
108 | done
109 | for af in ~/.config/autostart/* /etc/xdg/autostart/*; do
110 | grep -i "$svc" "$af" 2>/dev/null && echo " $af 含相关内容"
111 | done
112 | echo
113 |
114 | # 4. init.d/sysvinit(老系统)
115 | echo "4. init.d/sysvinit 相关:"
116 | [ -f "/etc/init.d/$svc" ] && echo " /etc/init.d/$svc"
117 | for r in /etc/rc*.d/*; do
118 | grep -i "$svc" "$r" 2>/dev/null && echo " $r 含相关内容"
119 | done
120 | echo
121 |
122 | # 5. 常见配置、数据、日志目录
123 | echo "5. 相关配置、数据、日志目录(实际存在的项):"
124 | for p in /etc/${svc}* ~/.config/${svc}* /var/lib/${svc}* /var/log/${svc}* /usr/local/etc/${svc}* /opt/${svc}*; do
125 | [ -e "$p" ] && echo " $p"
126 | done
127 | echo
128 |
129 | # 6. 服务相关用户和组
130 | echo "6. 服务相关用户和组:"
131 | grep "$svc" /etc/passwd && echo " /etc/passwd"
132 | grep "$svc" /etc/group && echo " /etc/group"
133 | echo
134 |
135 | echo "请人工确认以上项目后再手动清理!如有重要数据请提前备份。"
136 | } > "$checklist"
137 |
138 | success "已在 $checklist 生成 $svc 服务残留建议清单(均为实际查找到的项)。请查阅并按需手动处理。"
139 | info "部分清单内容如下:"
140 | head -20 "$checklist"
141 | }
142 |
143 | ### === 服务管理主逻辑 === ###
144 | manage_services() {
145 | info "正在收集服务列表,请稍候..."
146 |
147 | CUSTOM_UNIT_PATHS=(
148 | "/etc/systemd/system"
149 | "/usr/local/lib/systemd/system"
150 | )
151 | SYSTEM_UNIT_PATHS=(
152 | "/lib/systemd/system"
153 | "/usr/lib/systemd/system"
154 | )
155 |
156 | services_file=$(mktemp)
157 | systemctl list-unit-files --type=service | awk '/\.service/ {print $1}' | sort > "$services_file"
158 |
159 | declare -a all_svc
160 | declare -a all_type
161 | declare -a all_path
162 | declare -a all_active
163 | declare -a all_enabled
164 |
165 | idx=1
166 | while read -r svc; do
167 | path="-"
168 | type="系统"
169 | for u in "${CUSTOM_UNIT_PATHS[@]}"; do
170 | if [ -f "$u/$svc" ]; then
171 | path="$u/$svc"
172 | type="用户安装"
173 | break
174 | fi
175 | done
176 | if [ "$type" = "系统" ]; then
177 | for u in "${SYSTEM_UNIT_PATHS[@]}"; do
178 | if [ -f "$u/$svc" ]; then
179 | path="$u/$svc"
180 | break
181 | fi
182 | done
183 | fi
184 | all_svc[$idx]="$svc"
185 | all_type[$idx]="$type"
186 | all_path[$idx]="$path"
187 | all_active[$idx]="$(systemctl is-active "$svc" 2>/dev/null)"
188 | all_enabled[$idx]="$(systemctl is-enabled "$svc" 2>/dev/null)"
189 | idx=$((idx+1))
190 | done < "$services_file"
191 | rm -f "$services_file"
192 |
193 | # 展示“用户安装”优先
194 | declare -A idx_map
195 | show_idx=1
196 | echo
197 | printf "%-3s | %-45s | %-9s | %-8s | %-8s | %-8s\n" "No." "Service Name" "类型" "Active" "Enabled" "UnitPath"
198 | echo "-----------------------------------------------------------------------------------------------------"
199 |
200 | for i in "${!all_svc[@]}"; do
201 | if [[ "${all_type[$i]}" == "用户安装" && -n "${all_svc[$i]}" ]]; then
202 | printf "%-3s | %-45s | %-9s | %-8s | %-8s | %-8s\n" "$show_idx" "${all_svc[$i]}" "${all_type[$i]}" "${all_active[$i]}" "${all_enabled[$i]}" "${all_path[$i]}"
203 | idx_map[$show_idx]=$i
204 | show_idx=$((show_idx+1))
205 | fi
206 | done
207 | for i in "${!all_svc[@]}"; do
208 | if [[ "${all_type[$i]}" == "系统" && -n "${all_svc[$i]}" ]]; then
209 | printf "%-3s | %-45s | %-9s | %-8s | %-8s | %-8s\n" "$show_idx" "${all_svc[$i]}" "${all_type[$i]}" "${all_active[$i]}" "${all_enabled[$i]}" "${all_path[$i]}"
210 | idx_map[$show_idx]=$i
211 | show_idx=$((show_idx+1))
212 | fi
213 | done
214 |
215 | total=$((show_idx-1))
216 |
217 | echo ""
218 | read -p "请输入要操作的服务编号(如 12),多个用空格分隔,留空退出: " -a nums
219 | if [ "${#nums[@]}" = 0 ]; then
220 | info "无操作,退出。"
221 | exit $EXIT_SUCCESS
222 | fi
223 |
224 | echo ""
225 | echo "支持的操作:"
226 | echo "1. 关闭自启 (disable)"
227 | echo "2. 停止服务 (stop)"
228 | echo "3. 卸载服务(停止+关闭自启+删除unit文件+刷新,仅限用户安装服务)"
229 | echo "4. 仅查看状态 (status)"
230 | read -p "请输入操作编号 [1/2/3/4]: " action
231 |
232 | for n in "${nums[@]}"; do
233 | if ! [[ $n =~ ^[0-9]+$ ]] || [ "$n" -gt "$total" ] || [ "$n" -lt 1 ]; then
234 | warn "非法编号: $n 跳过"
235 | continue
236 | fi
237 |
238 | i=${idx_map[$n]}
239 | svc="${all_svc[$i]}"
240 | type="${all_type[$i]}"
241 | upath="${all_path[$i]}"
242 |
243 | echo ""
244 | info "处理服务: $svc [$type] ($upath)"
245 |
246 | case $action in
247 | 1)
248 | info "-> 关闭自启"
249 | systemctl disable "$svc"
250 | log "INFO" "禁用 $svc"
251 | ;;
252 | 2)
253 | info "-> 停止服务"
254 | systemctl stop "$svc"
255 | log "INFO" "停止 $svc"
256 | ;;
257 | 3)
258 | if [[ "$type" == "用户安装" ]]; then
259 | info "-> 停止服务"
260 | systemctl stop "$svc"
261 | info "-> 关闭自启"
262 | systemctl disable "$svc"
263 | if [[ -f "$upath" ]]; then
264 | read -p "确认要删除unit文件 $upath ? (y/n): " yn
265 | [[ "$yn" =~ ^[Yy]$ ]] && rm "$upath" && success "已删除 $upath" || warn "已取消删除"
266 | systemctl daemon-reload
267 | else
268 | warn "找不到 unit 文件,可能已被删除"
269 | fi
270 |
271 | # 插入生成清单和提示
272 | generate_checklist "$svc"
273 |
274 | success "用户安装服务 $svc 已尝试卸载"
275 | log "INFO" "用户安装服务 $svc 已卸载"
276 | else
277 | warn "系统服务不建议自动卸载!"
278 | fi
279 | ;;
280 | 4)
281 | systemctl status "$svc"
282 | ;;
283 | *)
284 | warn "不支持的操作"
285 | ;;
286 | esac
287 | done
288 |
289 | success "全部操作完成。"
290 | log "INFO" "全部操作完成"
291 | }
292 |
293 | ### === 主函数 === ###
294 | main() {
295 | echo -e "\033[33m[信息] $SCRIPT_NAME ,版本: $SCRIPT_VERSION\033[0m"
296 | echo -e "\033[33m[作者] $SCRIPT_AUTHOR\033[0m"
297 |
298 | log "INFO" "脚本 $SCRIPT_NAME (版本: $SCRIPT_VERSION) 开始执行"
299 | check_systemctl
300 | check_root
301 | check_dependencies
302 | manage_services
303 |
304 | exit $EXIT_SUCCESS
305 | }
306 |
307 | ### === 脚本入口 === ###
308 | main
--------------------------------------------------------------------------------
/shell_scripts/system_manage/terminal_setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: terminal_setup.sh
5 | # 功能: 这是一个终端优化与美化脚本,用于优化终端的展示效果与功能。
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-13
8 | # 许可证: MIT
9 |
10 | ### === 版本信息 === ###
11 | SCRIPT_VERSION="0.0.1"
12 | echo -e "\033[32m[信息] 脚本版本: $SCRIPT_VERSION\033[0m"
13 |
14 | ### === 退出状态码 === ###
15 | EXIT_SUCCESS=0
16 | EXIT_ERROR=1
17 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
18 |
19 | ### === 权限检查 === ###
20 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
21 |
22 | ### === 颜色定义 === ###
23 | RED='\033[0;31m'
24 | GREEN='\033[0;32m'
25 | YELLOW='\033[0;33m'
26 | CYAN='\033[0;36m'
27 | BLUE='\033[34m';
28 | NC='\033[0m'
29 |
30 | ### === 信号捕获 === ###
31 | cleanup() {
32 | log "INFO" "脚本被中断..."
33 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
34 | exit $EXIT_INTERRUPT
35 | }
36 | trap cleanup SIGINT SIGTERM
37 |
38 | # 日志文件
39 | LOG_FILE="/tmp/terminal_setup.log"
40 | echo "===== 终端配置脚本日志 ($(date)) =====" >> "$LOG_FILE"
41 |
42 | ### ==== 彩色输出函数 ==== ###
43 | info() { echo -e "$(date '+%Y-%m-%d %H:%M:%S') ${BLUE}[信息]${NC} $1" | tee -a "$LOG_FILE"; }
44 | success() { echo -e "$(date '+%Y-%m-%d %H:%M:%S') ${GREEN}[成功]${NC} $1" | tee -a "$LOG_FILE"; }
45 | warning() { echo -e "$(date '+%Y-%m-%d %H:%M:%S') ${YELLOW}[提示]${NC} $1" | tee -a "$LOG_FILE"; }
46 | error() { echo -e "$(date '+%Y-%m-%d %H:%M:%S') ${RED}[错误]${NC} $1" | tee -a "$LOG_FILE"; exit 1; }
47 |
48 |
49 | ### ==== 检测命令是否存在 ==== ###
50 |
51 | check_command() {
52 | local pkg="$1"
53 | info "检查命令 $pkg 是否存在..."
54 | if [[ "$pkg" == "bash-completion" ]]; then
55 | case "$OS_ID" in
56 | debian|ubuntu|linuxmint)
57 | dpkg -s bash-completion >/dev/null 2>&1 && return 0
58 | return 1
59 | ;;
60 | centos|rhel|fedora|rocky|almalinux)
61 | rpm -q bash-completion >/dev/null 2>&1 && return 0
62 | return 1
63 | ;;
64 | arch|manjaro)
65 | pacman -Qs bash-completion >/dev/null 2>&1 && return 0
66 | return 1
67 | ;;
68 | opensuse|suse)
69 | rpm -q bash-completion >/dev/null 2>&1 && return 0
70 | return 1
71 | ;;
72 | alpine)
73 | apk info bash-completion >/dev/null 2>&1 && return 0
74 | return 1
75 | ;;
76 | openwrt)
77 | opkg list-installed | grep -q bash-completion && return 0
78 | return 1
79 | ;;
80 | *)
81 | warning "无法检查 $pkg 的安装状态(未知发行版:$OS_ID)"
82 | return 1
83 | ;;
84 | esac
85 | else
86 | command -v "$pkg" >/dev/null 2>&1 && return 0
87 | return 1
88 | fi
89 | }
90 |
91 | ### ==== 检测发行版 ==== ###
92 | detect_os() {
93 | echo "[信息] 检测操作系统..." >&2 | tee -a "$LOG_FILE"
94 | if [[ -f /etc/os-release ]]; then
95 | . /etc/os-release
96 | if [[ -n "$ID" ]]; then
97 | echo "$ID" | tr -d '\n' | tr -s ' '
98 | else
99 | error "无法获取发行版 ID(/etc/os-release 格式错误)"
100 | fi
101 | elif command -v lsb_release >/dev/null 2>&1; then
102 | lsb_release -is | tr '[:upper:]' '[:lower:]' | tr -d '\n' | tr -s ' '
103 | elif [[ -f /etc/redhat-release ]]; then
104 | echo "centos"
105 | elif [[ -f /etc/debian_version ]]; then
106 | echo "debian"
107 | else
108 | error "无法检测发行版(缺少 /etc/os-release 或其他标识文件)"
109 | fi
110 | }
111 | OS_ID=$(detect_os)
112 | info "检测到发行版:$OS_ID"
113 |
114 | ### ==== 备份配置文件 ==== ###
115 | backup_config() {
116 | local file="$1"
117 | info "检查备份 $file..."
118 | if [[ -f "$file" ]]; then
119 | cp "$file" "${file}.bak-$(date +%F-%H%M%S)"
120 | success "已备份 $file"
121 | else
122 | warning "$file 不存在,无需备份"
123 | fi
124 | }
125 |
126 | ### ==== 安装单个软件包 ==== ###
127 | install_package() {
128 | local pkg="$1"
129 | info "处理软件包 $pkg..."
130 |
131 | if check_command "$pkg"; then
132 | success "$pkg 已安装,跳过"
133 | return 0
134 | fi
135 |
136 | # 验证 OS_ID
137 | info "当前 OS_ID:$OS_ID"
138 | if [[ -z "$OS_ID" || "$OS_ID" =~ [[:space:]] || "$OS_ID" =~ \[.*\] ]]; then
139 | error "无效的发行版 ID:$OS_ID"
140 | fi
141 |
142 | info "安装 $pkg..."
143 | case "$OS_ID" in
144 | debian|ubuntu|linuxmint)
145 | info "检查网络连接..."
146 | if ! curl -Is --connect-timeout 5 http://www.google.com >/dev/null; then
147 | warning "无法连接到网络,检查网络连接"
148 | return 1
149 | fi
150 | if ! apt update -y || ! apt install -y "$pkg"; then
151 | error "$pkg 安装失败,请检查包源(如 /etc/apt/sources.list)"
152 | fi
153 | ;;
154 | centos|rhel|fedora|rocky|almalinux)
155 | info "检测包管理器..."
156 | if command -v dnf >/dev/null 2>&1; then
157 | dnf -y update && dnf install -y epel-release && dnf install -y "$pkg" || error "$pkg 安装失败"
158 | elif command -v yum >/dev/null 2>&1; then
159 | yum -y update && yum install -y epel-release && yum install -y "$pkg" || error "$pkg 安装失败"
160 | else
161 | error "${OS_ID} 上未找到 yum 或 dnf"
162 | fi
163 | ;;
164 | arch|manjaro)
165 | pacman -Syu --noconfirm && pacman -S --noconfirm "$pkg" || error "$pkg 安装失败"
166 | ;;
167 | opensuse|suse)
168 | zypper refresh && zypper install -y "$pkg" || error "$pkg 安装失败"
169 | ;;
170 | alpine)
171 | apk update && apk add "$pkg" || error "$pkg 安装失败"
172 | ;;
173 | openwrt)
174 | opkg update && opkg install "$pkg" || error "$pkg 安装失败"
175 | ;;
176 | *)
177 | error "不支持的发行版:$OS_ID"
178 | ;;
179 | esac
180 |
181 | if check_command "$pkg"; then
182 | success "$pkg 安装成功"
183 | else
184 | error "$pkg 安装失败,请检查日志 $LOG_FILE"
185 | fi
186 | }
187 |
188 | ### ==== 移除软件包 ==== ###
189 | remove_package() {
190 | local pkg="$1"
191 | info "检查 $pkg 是否需要移除..."
192 | if ! check_command "$pkg"; then
193 | success "$pkg 未安装,跳过"
194 | return 0
195 | fi
196 | info "移除 $pkg..."
197 | case "$OS_ID" in
198 | debian|ubuntu|linuxmint)
199 | apt remove -y "$pkg" && apt autoremove -y
200 | ;;
201 | centos|rhel|fedora|rocky|almalinux)
202 | if command -v dnf >/dev/null 2>&1; then
203 | dnf remove -y "$pkg"
204 | elif command -v yum >/dev/null 2>&1; then
205 | yum remove -y "$pkg"
206 | fi
207 | ;;
208 | arch|manjaro)
209 | pacman -Rns --noconfirm "$pkg"
210 | ;;
211 | opensuse|suse)
212 | zypper remove -y "$pkg"
213 | ;;
214 | alpine)
215 | apk del "$pkg"
216 | ;;
217 | openwrt)
218 | opkg remove "$pkg"
219 | ;;
220 | *)
221 | warning "不支持的发行版:$OS_ID,无法移除 $pkg"
222 | return 1
223 | ;;
224 | esac
225 | if ! check_command "$pkg"; then
226 | success "$pkg 已移除"
227 | else
228 | warning "$pkg 移除失败,请检查日志 $LOG_FILE"
229 | fi
230 | }
231 |
232 | ### ==== 恢复备份配置 ==== ###
233 | restore_backup() {
234 | local file="$1"
235 | info "检查 $file 备份..."
236 | local backup
237 | backup=$(ls -t "${file}.bak-"* 2>/dev/null | head -n 1)
238 | if [[ -n "$backup" ]]; then
239 | info "恢复 $file 从 $backup..."
240 | cp "$backup" "$file"
241 | success "$file 已恢复"
242 | else
243 | warning "未找到 $file 的备份"
244 | fi
245 | }
246 |
247 | ### ==== Bash 优化 ==== ###
248 | bash_optimize() {
249 | info "开始 Bash 优化..."
250 | local packages=(git curl wget bash-completion)
251 | for pkg in "${packages[@]}"; do
252 | install_package "$pkg"
253 | done
254 |
255 | info "配置当前用户($USER)的 Bash 环境..."
256 | bash_config
257 | info "自动加载 ~/.bashrc 以生效配置..."
258 | if [[ -f ~/.bashrc ]]; then
259 | source ~/.bashrc 2>/dev/null || warning "无法立即应用 .bashrc,请手动 source"
260 | success "已加载 ~/.bashrc"
261 | else
262 | warning "~/.bashrc 不存在,跳过自动加载"
263 | fi
264 | }
265 |
266 | ### ==== Bash 配置 ==== ###
267 | bash_config() {
268 | info "配置 Bash 环境..."
269 | backup_config ~/.bashrc
270 | cat > ~/.bashrc <<'EOF'
271 | # 确保脚本在 Bash 中运行
272 | if [[ -z "$BASH_VERSION" ]]; then
273 | echo "错误:此脚本需在 Bash 中运行" >&2
274 | return 1
275 | fi
276 |
277 | # ==== PS1 美化 ====
278 | # 加载 Git 提示脚本(如果存在)
279 | for git_prompt in \
280 | "/usr/lib/git-core/git-prompt.sh" \
281 | "/usr/share/git-core/contrib/completion/git-prompt.sh" \
282 | "/etc/bash_completion.d/git-prompt"; do
283 | if [[ -f "$git_prompt" ]]; then
284 | source "$git_prompt"
285 | break
286 | fi
287 | done
288 |
289 | # 定义 PS1,包含 Git 分支
290 | if declare -f __git_ps1 >/dev/null; then
291 | GIT_PS1_SHOWDIRTYSTATE=1
292 | GIT_PS1_SHOWSTASHSTATE=1
293 | GIT_PS1_SHOWUNTRACKEDFILES=1
294 | PS1='\[\033[1;32m\]\D{%Y-%m-%d %H:%M} \u@\h:\w$(__git_ps1 " (%s)")#\[\033[0m\]\n\[\033[1;32m\]➤ \[\033[0m\]'
295 | else
296 | PS1='\[\033[1;32m\]\D{%Y-%m-%d %H:%M} \u@\h:\w#\[\033[0m\]\n\[\033[1;32m\]➤ \[\033[0m\]'
297 | fi
298 |
299 | # ==== 历史优化 ====
300 | HISTCONTROL=ignoredups:erasedups
301 | HISTSIZE=10000
302 | HISTFILESIZE=20000
303 | HISTTIMEFORMAT="%F %T "
304 | if type shopt >/dev/null 2>&1; then
305 | shopt -s histappend
306 | fi
307 | export PROMPT_COMMAND="history -a; $PROMPT_COMMAND"
308 |
309 | # ==== 环境变量 ====
310 | export EDITOR=nano
311 |
312 | # ==== 常用命令别名 ====
313 | alias ll='ls -l --color=auto' # 长格式列出文件
314 | alias la='ls -la --color=auto' # 列出所有文件,包括隐藏文件
315 | alias ls='ls --color=auto' # 彩色 ls 输出
316 | alias grep='grep --color=auto' # 彩色 grep 输出
317 | alias df='df -h' # 磁盘空间以人类可读格式显示
318 | alias du='du -h' # 文件大小以人类可读格式显示
319 | alias cp='cp -i' # 复制前确认
320 | alias mv='mv -i' # 移动前确认
321 | alias rm='rm -i' # 删除前确认
322 | alias free='free -h' # 内存使用以人类可读格式显示
323 | alias cls='clear' # 清除屏幕
324 | alias ping='ping -c 4' # ping 默认发送 4 次
325 | alias tailf='tail -f' # 实时查看文件尾部
326 | alias g='git' # 简写 git 命令
327 | alias v='vim' # 快速打开 vim
328 | alias t='tree' # 显示目录树
329 | alias c='clear' # 简写清除屏幕
330 | alias h='history' # 查看命令历史
331 | alias p='ps aux' # 查看所有进程
332 | alias nt='netstat -tuln' # 查看监听端口
333 | EOF
334 | source ~/.bashrc
335 | success "Bash 配置已写入 & 生效"
336 | }
337 |
338 | ### ==== 清理配置 ==== ###
339 | clean_config() {
340 | info "清理用户配置..."
341 | restore_backup ~/.bashrc
342 | success "用户配置已清理并还原"
343 | }
344 |
345 | ### ==== 还原&清理全部 ==== ###
346 | cleanup_all() {
347 | info "开始还原配置..."
348 | info "清理当前用户($USER)的配置..."
349 | clean_config
350 | }
351 |
352 | ### ==== 主菜单 ==== ###
353 | main_menu() {
354 | info "欢迎使用生产环境终端配置工具"
355 | echo -e "${YELLOW}请选择操作:${NC}"
356 | echo -e "1) bash 优化"
357 | echo -e "2) 还原&清理全部"
358 | read -t 30 -rp "请输入选项 [1-2,默认1]: " choice || choice="1"
359 | echo
360 | case "$choice" in
361 | 1)
362 | bash_optimize
363 | ;;
364 | 2)
365 | cleanup_all
366 | ;;
367 | *)
368 | warning "无效选项,默认执行 bash 优化"
369 | bash_optimize
370 | ;;
371 | esac
372 | }
373 |
374 | ### ==== 配置入口 ==== ###
375 | if [[ "$1" == "--bash-config" ]]; then
376 | bash_config
377 | elif [[ "$1" == "--clean-config" ]]; then
378 | clean_config
379 | elif [[ "$1" == "--help" ]]; then
380 | echo -e "${BLUE}生产环境终端配置工具${NC}"
381 | echo -e "用法:$0 [选项]"
382 | echo -e "选项:"
383 | echo -e " --bash-config 配置 Bash 环境"
384 | echo -e " --clean-config 清理用户配置并还原备份"
385 | echo -e " --help 显示此帮助信息"
386 | exit 0
387 | else
388 | main_menu
389 | fi
390 |
391 | echo -e "${GREEN}✅ 操作完成!日志已保存到 $LOG_FILE${NC}"
392 | echo -e "${GREEN}请运行 ${BLUE}source ~/.bashrc${GREEN} 以生效 Bash 配置,或重新打开终端。${NC}"
--------------------------------------------------------------------------------
/shell_scripts/system_reinstall/installnet.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: installnet.sh
5 | # 功能: InstallNET.sh 的交互式脚本,可以选择自己安装的系统。
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-20
8 | # 许可证: MIT
9 |
10 | ### === 版本信息 === ###
11 | SCRIPT_VERSION="0.0.2"
12 | SCRIPT_NAME="reinstall交互式安装脚本"
13 | SCRIPT_AUTHOR="[@Rouxyang] "
14 |
15 | echo -e "\033[33m[信息] $SCRIPT_NAME ,版本: $SCRIPT_VERSION\033[0m"
16 | echo -e "\033[33m[作者] $SCRIPT_AUTHOR\033[0m"
17 |
18 | ### === 退出状态码 === ###
19 | EXIT_SUCCESS=0
20 | EXIT_ERROR=1
21 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
22 |
23 | ### === 权限检查 === ###
24 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
25 |
26 | ### === 颜色定义 === ###
27 | RED='\033[0;31m'
28 | GREEN='\033[0;32m'
29 | YELLOW='\033[0;33m'
30 | CYAN='\033[0;36m'
31 | NC='\033[0m'
32 |
33 | ### === 彩色输出函数 === ###
34 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
35 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
36 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
37 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
38 |
39 | ### === 信号捕获 === ###
40 | cleanup() {
41 | log "INFO" "脚本被中断..."
42 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
43 | exit $EXIT_INTERRUPT
44 | }
45 | trap cleanup SIGINT SIGTERM
46 |
47 |
48 | ### === 工具检查 === ###
49 | check_dependencies() {
50 | for tool in curl wget; do
51 | if ! command -v $tool >/dev/null 2>&1; then
52 | echo -e "\033[31m[错误] 缺少依赖:$tool,请先安装!\033[0m"
53 | exit 1
54 | fi
55 | done
56 | }
57 |
58 |
59 | ### === 函数:定义系统和版本 === ###
60 | define_systems() {
61 | SYSTEMS=( "ubuntu" "debian" "centos" "alpine" "kali" "almalinux" "rockylinux" "fedora" "windows" )
62 | declare -gA VERSIONS
63 | VERSIONS["ubuntu"]="24.04 22.04 20.04"
64 | VERSIONS["debian"]="12 11 10 9 8 7"
65 | VERSIONS["centos"]="10 9 8 7"
66 | VERSIONS["alpine"]="edge 3.21 3.20 3.19 3.18"
67 | VERSIONS["kali"]="rolling"
68 | VERSIONS["almalinux"]="9 8"
69 | VERSIONS["rockylinux"]="9 8"
70 | VERSIONS["fedora"]="39 38"
71 | VERSIONS["windows"]="2022 2019 2016 2012 11 10"
72 | DEFAULT_PASSWORD="LeitboGi0ro"
73 | DEFAULT_PORT="22"
74 | }
75 |
76 | ### === 函数:选择系统 === ###
77 | select_system() {
78 | info "请选择要安装的系统:"
79 | select SYSTEM in "${SYSTEMS[@]}"; do
80 | if [[ -n "$SYSTEM" ]]; then
81 | success "已选择系统:$SYSTEM"
82 | break
83 | else
84 | warn "无效选择,请重试"
85 | fi
86 | done
87 | }
88 |
89 | ### === 函数:选择或自定义版本 === ###
90 | select_version() {
91 | VERSION=""
92 | if [[ -n "${VERSIONS[$SYSTEM]}" ]]; then
93 | OPTIONS=(${VERSIONS[$SYSTEM]})
94 | info "可用版本(降序):"
95 | select CHOICE in "${OPTIONS[@]}" "手动输入版本" "跳过(不指定)"; do
96 | if [[ "$CHOICE" == "跳过(不指定)" ]]; then
97 | VERSION=""
98 | info "不指定版本"
99 | break
100 | elif [[ "$CHOICE" == "手动输入版本" ]]; then
101 | read -p "请输入自定义版本号: " VERSION
102 | break
103 | elif [[ -n "$CHOICE" ]]; then
104 | VERSION="$CHOICE"
105 | success "已选择版本:$VERSION"
106 | break
107 | else
108 | warn "无效选择,请重试"
109 | fi
110 | done
111 | else
112 | info "$SYSTEM 无需指定版本"
113 | fi
114 | }
115 |
116 | ### === 函数:选择架构 === ###
117 | select_arch() {
118 | ARCH_FLAG=""
119 | if [[ "$SYSTEM" != "windows" ]]; then
120 | info "请选择架构(默认自动检测):"
121 | select ARCH in "64-bit" "32-bit" "arm64" "跳过(自动检测)"; do
122 | if [[ -z "$REPLY" ]]; then
123 | ARCH_FLAG=""
124 | break
125 | fi
126 | case "$ARCH" in
127 | "64-bit") ARCH_FLAG="-v 64"; break ;;
128 | "32-bit") ARCH_FLAG="-v 32"; break ;;
129 | "arm64") ARCH_FLAG="-v arm64"; break ;;
130 | "跳过(自动检测)") ARCH_FLAG=""; break ;;
131 | *) warn "无效选择,请重试" ;;
132 | esac
133 | done
134 | fi
135 | }
136 |
137 | ### === 函数:设置密码 === ###
138 | input_password() {
139 | warn "请输入密码(留空使用默认密码): "
140 | read -rs PASSWORD
141 | echo
142 | PASSWORD=${PASSWORD:-$DEFAULT_PASSWORD}
143 | PASSWORD_ARG="-pwd '$PASSWORD'"
144 | success "使用密码:$PASSWORD"
145 | }
146 |
147 | ### === 函数:设置 SSH 端口 === ###
148 | input_ssh_port() {
149 | echo -en "${YELLOW}请输入 SSH 端口(默认 $DEFAULT_PORT): ${NC}"
150 | read SSH_PORT
151 | SSH_PORT=${SSH_PORT:-$DEFAULT_PORT}
152 | SSH_PORT_ARG="-port $SSH_PORT"
153 | success "SSH 端口:$SSH_PORT"
154 | }
155 |
156 | ### === 函数:设置镜像源或 Windows 镜像 === ###
157 | input_mirror_or_url() {
158 | MIRROR_ARG=""
159 | if [[ "$SYSTEM" != "windows" ]]; then
160 | echo -en "${YELLOW}请输入自定义镜像源(留空使用默认): ${NC}"
161 | read MIRROR
162 | [[ -n "$MIRROR" ]] && MIRROR_ARG="--mirror '$MIRROR'"
163 | else
164 | echo -en "${YELLOW}请输入 Windows 镜像 URL: ${NC}"
165 | read WINDOWS_URL
166 | if [[ -z "$WINDOWS_URL" ]]; then
167 | error "Windows 安装必须提供镜像 URL"
168 | exit 1
169 | fi
170 | fi
171 | }
172 |
173 | ### === 函数:设置网络参数 === ###
174 | input_network_params() {
175 | NET_ARG=""
176 | echo -en "${YELLOW}是否自定义网络参数?(y/n): ${NC}"
177 | read NET_CHOICE
178 | if [[ "$NET_CHOICE" =~ ^[Yy]$ ]]; then
179 | read -p "IPv4 地址(留空使用 DHCP): " IP4_ADDR
180 | if [[ -n "$IP4_ADDR" ]]; then
181 | read -p "IPv4 子网掩码: " IP4_MASK
182 | read -p "IPv4 网关: " IP4_GATE
183 | read -p "IPv4 DNS(默认 8.8.8.8 1.1.1.1): " IP4_DNS
184 | IP4_DNS=${IP4_DNS:-"8.8.8.8 1.1.1.1"}
185 | NET_ARG="$NET_ARG --ip-addr '$IP4_ADDR' --ip-mask '$IP4_MASK' --ip-gate '$IP4_GATE' --ip-dns '$IP4_DNS'"
186 | fi
187 | read -p "IPv6 地址(留空跳过): " IP6_ADDR
188 | if [[ -n "$IP6_ADDR" ]]; then
189 | read -p "IPv6 前缀长度: " IP6_MASK
190 | read -p "IPv6 网关: " IP6_GATE
191 | read -p "IPv6 DNS(默认 2001:4860:4860::8888): " IP6_DNS
192 | IP6_DNS=${IP6_DNS:-"2001:4860:4860::8888 2606:4700:4700::1111"}
193 | NET_ARG="$NET_ARG --ip6-addr '$IP6_ADDR' --ip6-mask '$IP6_MASK' --ip6-gate '$IP6_GATE' --ip6-dns '$IP6_DNS'"
194 | else
195 | NET_ARG="$NET_ARG --setipv6 '0'"
196 | fi
197 | fi
198 | }
199 |
200 | ### === 函数:构建命令 === ###
201 | build_command() {
202 | CMD="bash <(wget -qO- https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh)"
203 | case "$SYSTEM" in
204 | "windows") CMD="$CMD -dd '$WINDOWS_URL'" ;;
205 | *) CMD="$CMD -$SYSTEM $VERSION $ARCH_FLAG" ;;
206 | esac
207 | CMD="$CMD $PASSWORD_ARG $SSH_PORT_ARG $MIRROR_ARG $NET_ARG"
208 | }
209 |
210 | ### === 函数:执行确认 === ###
211 | confirm_and_run() {
212 | info "即将执行命令:"
213 | echo -e "${BOLD}${CMD}${NC}"
214 | echo -en "${YELLOW}是否确认执行?此操作将格式化系统盘!(y/n): ${NC}"
215 | read CONFIRM
216 | if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
217 | success "开始执行安装流程..."
218 | eval "$CMD"
219 | else
220 | warn "已取消执行。"
221 | exit 0
222 | fi
223 | }
224 |
225 | ### === 主流程 === ###
226 | main() {
227 | check_root
228 | check_dependencies
229 | define_systems
230 |
231 | info "欢迎使用 InstallNET.sh 安装脚本!"
232 | info "Github: https://github.com/leitbogioro/Tools"
233 | info "当前时间:$(date '+%Y-%m-%d %H:%M:%S')"
234 |
235 | select_system
236 | select_version
237 | select_arch
238 | input_password
239 | input_ssh_port
240 | input_mirror_or_url
241 | input_network_params
242 | build_command
243 | confirm_and_run
244 | }
245 |
246 | main
247 |
--------------------------------------------------------------------------------
/shell_scripts/system_reinstall/reinstall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: reinstall.sh
5 | # 功能: reinstall 的交互式脚本,可以选择自己安装的系统。
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-20
8 | # 许可证: MIT
9 |
10 | ### === 版本信息 === ###
11 | SCRIPT_VERSION="0.0.2"
12 | SCRIPT_NAME="reinstall交互式安装脚本"
13 | SCRIPT_AUTHOR="[@Rouxyang] "
14 |
15 | echo -e "\033[33m[信息] $SCRIPT_NAME ,版本: $SCRIPT_VERSION\033[0m"
16 | echo -e "\033[33m[作者] $SCRIPT_AUTHOR\033[0m"
17 |
18 | ### === 退出状态码 === ###
19 | EXIT_SUCCESS=0
20 | EXIT_ERROR=1
21 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
22 |
23 | ### === 权限检查 === ###
24 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
25 |
26 | ### === 颜色定义 === ###
27 | RED='\033[0;31m'
28 | GREEN='\033[0;32m'
29 | YELLOW='\033[0;33m'
30 | CYAN='\033[0;36m'
31 | NC='\033[0m'
32 |
33 | ### === 彩色输出函数 === ###
34 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
35 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
36 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
37 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
38 |
39 | ### === 信号捕获 === ###
40 | cleanup() {
41 | log "INFO" "脚本被中断..."
42 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
43 | exit $EXIT_INTERRUPT
44 | }
45 | trap cleanup SIGINT SIGTERM
46 |
47 |
48 |
49 | ### === 工具检查 === ###
50 | check_dependencies() {
51 | for tool in curl wget; do
52 | if ! command -v $tool >/dev/null 2>&1; then
53 | echo -e "\033[31m[错误] 缺少依赖:$tool,请先安装!\033[0m"
54 | exit 1
55 | fi
56 | done
57 | }
58 |
59 |
60 |
61 | ### === 变量定义 === ###
62 | SYSTEM=""
63 | VERSION=""
64 | IMAGE_URL=""
65 | SSH_PORT=22
66 | PASSWORD=""
67 | CMD=""
68 | MODE=""
69 |
70 | ### === 系统选择 === ###
71 | select_system() {
72 | SYSTEMS=("ubuntu" "debian" "centos" "alpine" "kali" "almalinux" "rocky" "arch" "fedora" "opensuse" "oracle"
73 | "redhat" "anolis" "opencloudos" "almalinux" "nixos" "openeuler"
74 | "windows" "dd" "alpine-live" "netboot.xyz")
75 |
76 | info "请选择安装模式或系统:"
77 | select SYSTEM in "${SYSTEMS[@]}"; do
78 | if [[ -n "$SYSTEM" ]]; then
79 | success "已选择系统/模式:$SYSTEM"
80 | break
81 | else
82 | warn "无效选择,请重试"
83 | fi
84 | done
85 | }
86 |
87 | ### === 版本选择 === ###
88 | select_version() {
89 | declare -A VERSIONS
90 | VERSIONS["ubuntu"]="25.04 24.04 22.04 20.04 18.04 16.04"
91 | VERSIONS["debian"]="12 11 10 9"
92 | VERSIONS["centos"]="10 9"
93 | VERSIONS["alpine"]="3.21 3.20 3.19 3.18"
94 | VERSIONS["fedora"]="42 41"
95 | VERSIONS["opensuse"]="tumbleweed 15.6"
96 | VERSIONS["almalinux"]="9 8"
97 | VERSIONS["rocky"]="9 8"
98 | VERSIONS["oracle"]="9 8"
99 | VERSIONS["redhat"]="9 8"
100 | VERSIONS["anolis"]="23 8 7"
101 | VERSIONS["opencloudos"]="23 9 8"
102 | VERSIONS["almalinux"]="9 8"
103 | VERSIONS["nixos"]="24.11"
104 | VERSIONS["openeuler"]="25.03 24.03 22.03 20.03"
105 |
106 | if [[ -n "${VERSIONS[$SYSTEM]}" ]]; then
107 | info "请选择版本或手动输入:"
108 | select CHOICE in ${VERSIONS[$SYSTEM]} "手动输入" "跳过"; do
109 | if [[ "$CHOICE" == "跳过" ]]; then
110 | VERSION=""
111 | break
112 | elif [[ "$CHOICE" == "手动输入" ]]; then
113 | read -p "请输入版本号: " VERSION
114 | break
115 | elif [[ -n "$CHOICE" ]]; then
116 | VERSION="$CHOICE"
117 | break
118 | else
119 | warn "无效选择,请重试"
120 | fi
121 | done
122 | else
123 | info "$SYSTEM 无需指定版本"
124 | fi
125 | }
126 |
127 | ### === 获取密码 === ###
128 | get_password() {
129 | warn "请输入密码(留空则使用默认密码):"
130 | read -rs PASSWORD
131 | echo
132 | if [[ -z "$PASSWORD" ]]; then
133 | PASSWORD="123@@@"
134 | success "已使用默认密码:$PASSWORD"
135 | else
136 | success "您设置的密码是:$PASSWORD"
137 | fi
138 | }
139 |
140 | ### === 获取 SSH 端口 === ###
141 | get_ssh_port() {
142 | echo -en "${YELLOW}请输入 SSH 端口(默认 22): ${NC}"
143 | read SSH_PORT
144 | SSH_PORT=${SSH_PORT:-22}
145 | success "使用的 SSH 端口为:$SSH_PORT"
146 | }
147 |
148 | ### === 获取镜像地址 === ###
149 | get_image_url() {
150 | if [[ "$SYSTEM" == "dd" ]]; then
151 | read -p "请输入 DD 镜像地址(支持 http/https/gz/xz/zst/tar 等): " IMAGE_URL
152 | [[ -z "$IMAGE_URL" ]] && error "必须输入镜像地址!" && exit 1
153 | elif [[ "$SYSTEM" == "windows" ]]; then
154 | read -p "请输入 ISO 镜像名称或 image-name(例如 Windows 11 Pro): " IMAGE_NAME
155 | read -p "是否指定 ISO 下载地址?(可留空自动查找): " ISO_URL
156 | fi
157 | }
158 |
159 | ### === 构建安装命令 === ###
160 | build_command() {
161 | BASE_CMD="bash <(curl -sL https://raw.githubusercontent.com/bin456789/reinstall/main/reinstall.sh)"
162 |
163 | case "$SYSTEM" in
164 | dd)
165 | CMD="$BASE_CMD dd --img "$IMAGE_URL" --password "$PASSWORD" --ssh-port $SSH_PORT"
166 | ;;
167 | alpine-live)
168 | CMD="$BASE_CMD alpine --password "$PASSWORD" --ssh-port $SSH_PORT --hold=1"
169 | ;;
170 | netboot.xyz)
171 | CMD="$BASE_CMD netboot.xyz"
172 | ;;
173 | windows)
174 | CMD="$BASE_CMD windows --image-name "$IMAGE_NAME""
175 | [[ -n "$ISO_URL" ]] && CMD="$CMD --iso "$ISO_URL""
176 | CMD="$CMD --password "$PASSWORD" --ssh-port $SSH_PORT"
177 | ;;
178 | *)
179 | CMD="$BASE_CMD "$SYSTEM""
180 | [[ -n "$VERSION" ]] && CMD="$CMD "$VERSION""
181 | CMD="$CMD --password "$PASSWORD" --ssh-port $SSH_PORT"
182 | ;;
183 | esac
184 | }
185 |
186 | ### === 执行确认 === ###
187 | confirm_and_execute() {
188 | info "即将执行命令:"
189 | echo -e "${BOLD}${CMD}${NC}"
190 | echo -en "${YELLOW}是否确认执行?执行后将抹除当前系统所有数据!!!(y/n): ${NC}"
191 | read CONFIRM
192 | if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
193 | success "开始执行安装..."
194 | eval "$CMD"
195 | else
196 | warn "已取消安装流程"
197 | exit 0
198 | fi
199 | }
200 |
201 | ### === 主函数入口 === ###
202 | main() {
203 |
204 | check_dependencies
205 |
206 | info "欢迎使用 一键DD/重装脚本 (One-click reinstall OS on VPS)"
207 | info "Github: https://github.com/bin456789/reinstall"
208 | info "当前时间:$(date '+%Y-%m-%d %H:%M:%S')"
209 |
210 | select_system
211 |
212 | case "$SYSTEM" in
213 | dd|getimg|windows)
214 | get_image_url
215 | ;;
216 | netboot.xyz|alpine-live)
217 | ;;
218 | *)
219 | select_version
220 | ;;
221 | esac
222 |
223 | get_password
224 | get_ssh_port
225 | build_command
226 | confirm_and_execute
227 | }
228 |
229 | main
230 |
--------------------------------------------------------------------------------
/shell_scripts/utility_tools/auto_mount_disk.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: auto_mount_disk.sh
5 | # 功能: 这是一个脚本挂载脚本
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-13
8 |
9 | ### === 版本信息 === ###
10 | SCRIPT_VERSION="0.0.1"
11 | echo -e "\033[32m[信息] 脚本版本: $SCRIPT_VERSION\033[0m"
12 |
13 | ### === 退出状态码 === ###
14 | EXIT_SUCCESS=0
15 | EXIT_ERROR=1
16 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
17 |
18 | ### === 权限检查 === ###
19 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
20 |
21 | ### === 颜色定义 === ###
22 | RED='\033[0;31m'
23 | GREEN='\033[0;32m'
24 | YELLOW='\033[0;33m'
25 | CYAN='\033[0;36m'
26 | BLUE='\033[34m';
27 | NC='\033[0m'
28 |
29 |
30 | ### === 彩色输出函数 === ###
31 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
32 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
33 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
34 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
35 |
36 | ### === 信号捕获 === ###
37 | cleanup() {
38 | log "INFO" "脚本被中断..."
39 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
40 | exit $EXIT_INTERRUPT
41 | }
42 | trap cleanup SIGINT SIGTERM
43 |
44 | ### === 逻辑正式开始 === ###
45 |
46 | # System info
47 | sys_id=$(cat /etc/os-release | grep ^ID= | cut -d'=' -f2 | tr -d '"')
48 |
49 | # Software dependencies
50 | software_list=("parted" "util-linux")
51 |
52 |
53 | # Install software
54 | install_software() {
55 |
56 | if [ ${#software_list[@]} -eq 0 ]; then
57 | danger "software_list 中未指定任何软件包"
58 | exit 1
59 | fi
60 |
61 | check_command() {
62 | command -v "$1" &>/dev/null
63 | }
64 |
65 | install_package() {
66 | local pkg="$1"
67 | info "正在处理 $pkg..."
68 |
69 | if check_command "$pkg"; then
70 | success "$pkg 已安装"
71 | return 0
72 | fi
73 |
74 | info "正在安装 $pkg..."
75 | case ${sys_id} in
76 | centos|rhel|fedora|rocky|almalinux)
77 | if check_command dnf; then
78 | dnf -y update &>/dev/null && dnf install -y epel-release &>/dev/null
79 | dnf install -y "$pkg" &>/dev/null
80 | elif check_command yum; then
81 | yum -y update &>/dev/null && yum install -y epel-release &>/dev/null
82 | yum install -y "$pkg" &>/dev/null
83 | else
84 | danger "${sys_id} 上未找到 yum 或 dnf"
85 | return 1
86 | fi
87 | ;;
88 | debian|ubuntu|linuxmint)
89 | apt update -y &>/dev/null
90 | apt install -y "$pkg" &>/dev/null
91 | ;;
92 | arch|manjaro)
93 | if check_command pacman; then
94 | pacman -Syu --noconfirm &>/dev/null
95 | pacman -S --noconfirm "$pkg" &>/dev/null
96 | else
97 | danger "${sys_id} 上未找到 pacman"
98 | return 1
99 | fi
100 | ;;
101 | opensuse|suse)
102 | if check_command zypper; then
103 | zypper refresh &>/dev/null
104 | zypper install -y "$pkg" &>/dev/null
105 | else
106 | danger "${sys_id} 上未找到 zypper"
107 | return 1
108 | fi
109 | ;;
110 | alpine)
111 | if check_command apk; then
112 | apk update &>/dev/null
113 | apk add "$pkg" &>/dev/null
114 | else
115 | danger "${sys_id} 上未找到 apk"
116 | return 1
117 | fi
118 | ;;
119 | openwrt)
120 | if check_command opkg; then
121 | opkg update &>/dev/null
122 | opkg install "$pkg" &>/dev/null
123 | else
124 | danger "${sys_id} 上未找到 opkg"
125 | return 1
126 | fi
127 | ;;
128 | *)
129 | danger "未知系统: ${sys_id},请手动安装 $pkg"
130 | return 1
131 | ;;
132 | esac
133 |
134 | }
135 |
136 | local failed=0
137 | for pkg in "${software_list[@]}"; do
138 | install_package "$pkg" || failed=1
139 | done
140 |
141 | if [ $failed -eq 1 ]; then
142 | danger "一个或多个软件包安装失败"
143 | exit 1
144 | fi
145 | }
146 |
147 | # Auto-mount disk
148 | auto_mount_disk() {
149 | clear
150 | install_software
151 | info "正在检测可用磁盘..."
152 | local sys_disk=$(cat /proc/partitions | grep -v name | grep -v ram | awk '{print $4}' | grep -v '^$' | grep -v '[0-9]$' | grep -v 'vda' | grep -v 'xvda' | grep -v 'sda' | grep -e 'vd' -e 'sd' -e 'xvd')
153 | if [ -z "$sys_disk" ]; then
154 | danger "此服务器只有一块磁盘,无法挂载"
155 | return 1
156 | fi
157 |
158 | lsblk -d -o NAME,SIZE,MODEL | grep -v "NAME" || warn "未检测到可用磁盘"
159 |
160 | read -p "请输入磁盘设备名 (例如 sdb): " disk
161 | if [ ! -b "/dev/$disk" ]; then
162 | danger "磁盘 /dev/$disk 不存在"
163 | return 1
164 | fi
165 |
166 | if lsblk "/dev/$disk" | grep -q "/"; then
167 | warn "磁盘 /dev/$disk 已被挂载"
168 | return 0
169 | fi
170 |
171 | if fdisk -l "/dev/$disk" 2>/dev/null | grep -q "NTFS\|FAT32"; then
172 | danger "检测到 Windows 分区,为数据安全,请手动挂载"
173 | return 1
174 | fi
175 |
176 | info "选择文件系统格式"
177 | echo "1. ext4 (默认)"
178 | echo "2. xfs"
179 | echo "3. btrfs"
180 | read -p "请输入选择 (1-3,默认为 ext4): " fs_choice
181 | case $fs_choice in
182 | 2)
183 | filesystem="xfs"
184 | software_list=("xfsprogs")
185 | install_software
186 | ;;
187 | 3)
188 | filesystem="btrfs"
189 | software_list=("btrfs-progs")
190 | install_software
191 | ;;
192 | *)
193 | filesystem="ext4"
194 | ;;
195 | esac
196 |
197 | read -p "请输入挂载点 (默认为 /mnt/$disk): " mount_point
198 | mount_point=${mount_point:-/mnt/$disk}
199 | mkdir -p "$mount_point"
200 |
201 | if mount | grep -q "$mount_point"; then
202 | danger "挂载点 $mount_point 已被使用"
203 | return 1
204 | fi
205 |
206 | info "正在为 /dev/$disk 分区..."
207 | parted -s "/dev/$disk" mklabel gpt
208 | parted -s "/dev/$disk" mkpart primary "$filesystem" 0% 100%
209 | sleep 2
210 |
211 | info "正在格式化 /dev/${disk}1 为 $filesystem..."
212 | case $filesystem in
213 | ext4) mkfs.ext4 "/dev/${disk}1" >/dev/null 2>&1 ;;
214 | xfs) mkfs.xfs "/dev/${disk}1" >/dev/null 2>&1 ;;
215 | btrfs) mkfs.btrfs "/dev/${disk}1" >/dev/null 2>&1 ;;
216 | esac
217 | if [ $? -ne 0 ]; then
218 | danger "无法格式化 /dev/${disk}1"
219 | return 1
220 | fi
221 |
222 | info "正在挂载 /dev/${disk}1 到 $mount_point..."
223 | mount "/dev/${disk}1" "$mount_point"
224 | if [ $? -ne 0 ]; then
225 | danger "无法挂载 /dev/${disk}1"
226 | return 1
227 | fi
228 |
229 | disk_uuid=$(blkid -s UUID -o value "/dev/${disk}1")
230 | if ! grep -q "$disk_uuid" /etc/fstab; then
231 | echo "UUID=$disk_uuid $mount_point $filesystem defaults 0 2" >> /etc/fstab
232 | info "已将 /dev/${disk}1 添加到 /etc/fstab"
233 | fi
234 |
235 | mount -a
236 | if mount | grep -q "$mount_point"; then
237 | success "磁盘 /dev/${disk}1 已成功挂载到 $mount_point"
238 | else
239 | danger "挂载验证失败"
240 | return 1
241 | fi
242 | }
243 |
244 | # Main execution
245 | auto_mount_disk
--------------------------------------------------------------------------------
/shell_scripts/utility_tools/crontab_management.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: crontab_management.sh
5 | # 功能: 这是一个计划任务管理脚本
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-13
8 |
9 | ### === 版本信息 === ###
10 | SCRIPT_VERSION="0.0.1" # Updated version
11 | echo -e "\033[32m[信息] 脚本版本: $SCRIPT_VERSION\033[0m"
12 |
13 | ### === 退出状态码 === ###
14 | EXIT_SUCCESS=0
15 | EXIT_ERROR=1
16 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
17 |
18 | ### === 权限检查 === ###
19 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
20 |
21 | ### === 颜色定义 === ###
22 | RED='\033[0;31m'
23 | GREEN='\033[0;32m'
24 | YELLOW='\033[0;33m'
25 | CYAN='\033[0;36m'
26 | NC='\033[0m'
27 |
28 | ### === 彩色输出函数 === ###
29 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
30 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
31 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
32 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
33 |
34 | ### === 信号捕获 === ###
35 | cleanup() {
36 | log "INFO" "脚本被中断..."
37 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
38 | exit $EXIT_INTERRUPT
39 | }
40 | trap cleanup SIGINT SIGTERM
41 |
42 | # Manage crontab
43 | manage_crontab() {
44 | clear
45 | while true; do
46 | info "定时任务列表"
47 | crontab -l 2>/dev/null || echo "未找到定时任务"
48 | echo ""
49 | info "操作选项"
50 | echo "------------------------"
51 | echo "1. 添加定时任务"
52 | echo "2. 删除定时任务"
53 | echo "0. 退出"
54 | echo "------------------------"
55 | read -p "请输入您的选择: " choice
56 |
57 | case $choice in
58 | 1)
59 | read -p "请输入要调度的命令: " command
60 | if [ -z "$command" ]; then
61 | danger "命令不能为空"
62 | continue
63 | fi
64 | echo "------------------------"
65 | echo "1. 每周任务"
66 | echo "2. 每日任务"
67 | echo "3. 每分钟任务"
68 | read -p "选择调度类型: " schedule_type
69 |
70 | case $schedule_type in
71 | 1)
72 | read -p "选择星期几执行 (0-6,0=星期日): " weekday
73 | if [[ ! "$weekday" =~ ^[0-6]$ ]]; then
74 | danger "无效的星期值,必须为 0-6"
75 | continue
76 | fi
77 | (crontab -l 2>/dev/null; echo "0 0 * * $weekday $command") | crontab - >/dev/null 2>&1
78 | success "已添加每周定时任务"
79 | ;;
80 | 2)
81 | read -p "选择每天的执行小时 (0-23): " hour
82 | if [[ ! "$hour" =~ ^[0-9]+$ || $hour -lt 0 || $hour -gt 23 ]]; then
83 | danger "无效的小时值,必须为 0-23"
84 | continue
85 | fi
86 | (crontab -l 2>/dev/null; echo "0 $hour * * * $command") | crontab - >/dev/null 2>&1
87 | success "已添加每日定时任务"
88 | ;;
89 | 3)
90 | (crontab -l 2>/dev/null; echo "* * * * * $command") | crontab - >/dev/null 2>&1
91 | success "已添加每分钟定时任务"
92 | ;;
93 | *)
94 | danger "无效的调度类型"
95 | ;;
96 | esac
97 | ;;
98 | 2)
99 | read -p "请输入要删除的任务关键字: " keyword
100 | if [ -z "$keyword" ]; then
101 | danger "关键字不能为空"
102 | continue
103 | fi
104 | crontab -l | grep -v "$keyword" | crontab - >/dev/null 2>&1
105 | success "已删除包含 '$keyword' 的定时任务"
106 | ;;
107 | 0)
108 | break
109 | ;;
110 | *)
111 | danger "无效的选择"
112 | ;;
113 | esac
114 | echo ""
115 | info "按回车继续..."
116 | read -r
117 | done
118 | }
119 |
120 | # Main execution
121 | manage_crontab
--------------------------------------------------------------------------------
/shell_scripts/utility_tools/geek_prompt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: geek_prompt.sh
5 | # 功能: 增强 Shell 提示符显示效果,集成 Git 分支、高亮状态等信息
6 | # 作者: 3az7qmfd
7 | # 创建日期: 2025-04-21
8 |
9 | ### === 版本信息 === ###
10 | SCRIPT_VERSION="0.0.1"
11 | echo -e "\033[32m[信息] 脚本版本: $SCRIPT_VERSION\033[0m"
12 |
13 | ### === 退出状态码 === ###
14 | EXIT_SUCCESS=0
15 | EXIT_ERROR=1
16 | EXIT_INTERRUPT=130
17 |
18 | ### === 颜色定义 === ###
19 | RED='\033[0;31m'
20 | GREEN='\033[0;32m'
21 | YELLOW='\033[0;33m'
22 | CYAN='\033[0;36m'
23 | NC='\033[0m'
24 |
25 | ### === 彩色输出函数 === ###
26 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
27 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
28 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
29 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
30 |
31 | ### === 信号捕获 === ###
32 | cleanup() {
33 | warn "脚本被中断..."
34 | exit $EXIT_INTERRUPT
35 | }
36 | trap cleanup SIGINT SIGTERM
37 |
38 | ### === 主逻辑 === ###
39 | install_geek_prompt() {
40 | info "[开始] 安装 Geek Prompt..."
41 | cat > ~/.geek_prompt.sh <<"EOF"
42 | #!/bin/bash
43 |
44 | # 定义颜色(增强对比度)
45 | RESET="\[\033[0m\]"
46 | FG_WHITE="\[\033[1;97m\]" # 用户名@主机
47 | FG_BLUE="\[\033[1;94m\]" # 当前路径
48 | FG_YELLOW="\[\033[1;93m\]" # Git 分支
49 | FG_GREEN="\[\033[1;92m\]" # 提示符
50 | FG_RED="\[\033[1;91m\]" # 错误提示
51 |
52 | # macOS 与 Linux 的时间命令兼容性
53 | if [[ "$OSTYPE" == "darwin"* ]]; then
54 | DATE_CMD='gdate'
55 | else
56 | DATE_CMD='date'
57 | fi
58 |
59 | # 获取 Git 分支
60 | git_branch() {
61 | branch=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)
62 | if [[ -n "$branch" ]]; then
63 | if [[ -n $(git status --porcelain 2>/dev/null) ]]; then
64 | echo " [$FG_RED$branch$RESET]"
65 | else
66 | echo " [$FG_YELLOW$branch$RESET]"
67 | fi
68 | fi
69 | }
70 |
71 | __cmd_timer_start() {
72 | TIMER_START=$($DATE_CMD +%s)
73 | }
74 |
75 | __cmd_timer_end() {
76 | local TIMER_END=$($DATE_CMD +%s)
77 | local DIFF=$((TIMER_END - TIMER_START))
78 | if [[ $DIFF -gt 0 ]]; then
79 | CMD_TIME="(${FG_YELLOW}$(printf "%02d:%02d" $((DIFF/60)) $((DIFF%60)))$RESET) "
80 | else
81 | CMD_TIME=""
82 | fi
83 | }
84 |
85 | __cmd_exit_status() {
86 | local EXIT_CODE=$?
87 | if [[ $EXIT_CODE -ne 0 ]]; then
88 | EXIT_STATUS="[${FG_RED}✘ $EXIT_CODE${RESET}] "
89 | else
90 | EXIT_STATUS=""
91 | fi
92 | }
93 |
94 | __update_prompt() {
95 | PS1="${EXIT_STATUS}${CMD_TIME}${FG_WHITE}\u@\h ${FG_BLUE}\w$(git_branch) ${FG_GREEN}❯ ${RESET}"
96 | }
97 |
98 | export PROMPT_COMMAND='__cmd_exit_status; __cmd_timer_end; __update_prompt; __cmd_timer_start'
99 | EOF
100 |
101 | if ! grep -q "source ~/.geek_prompt.sh" ~/.bashrc; then
102 | echo "source ~/.geek_prompt.sh" >> ~/.bashrc
103 | success "已添加到 ~/.bashrc"
104 | else
105 | warn "已存在 ~/.bashrc 中,无需重复添加"
106 | fi
107 |
108 | # 立即生效
109 | source ~/.geek_prompt.sh
110 | success "[完成] Geek Bash Prompt 已安装并生效!"
111 | }
112 |
113 | # 执行安装
114 | install_geek_prompt
115 |
--------------------------------------------------------------------------------
/shell_scripts/utility_tools/hostname_management.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: hostname_management.sh
5 | # 功能: 这是一个主机名管理脚本,用于永久修改本机的主机名
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-13
8 |
9 | ### === 版本信息 === ###
10 | SCRIPT_VERSION="0.0.1"
11 | echo -e "\033[32m[信息] 脚本版本: $SCRIPT_VERSION\033[0m"
12 |
13 | ### === 退出状态码 === ###
14 | EXIT_SUCCESS=0
15 | EXIT_ERROR=1
16 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
17 |
18 | ### === 权限检查 === ###
19 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
20 |
21 | ### === 颜色定义 === ###
22 | RED='\033[0;31m'
23 | GREEN='\033[0;32m'
24 | YELLOW='\033[0;33m'
25 | CYAN='\033[0;36m'
26 | BLUE='\033[34m';
27 | NC='\033[0m'
28 |
29 |
30 | ### === 彩色输出函数 === ###
31 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
32 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
33 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
34 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
35 |
36 | ### === 信号捕获 === ###
37 | cleanup() {
38 | log "INFO" "脚本被中断..."
39 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
40 | exit $EXIT_INTERRUPT
41 | }
42 | trap cleanup SIGINT SIGTERM
43 |
44 | # Modify hostname
45 | # Modify hostname
46 | modify_hostname() {
47 | clear
48 | local current_hostname=$(hostname)
49 | info "当前主机名: $current_hostname"
50 |
51 | read -p "请输入新的主机名: " new_hostname
52 | if [ -z "$new_hostname" ]; then
53 | danger "主机名不能为空"
54 | return 1
55 | fi
56 |
57 | # Validate hostname (basic check for RFC 1123 compliance)
58 | if ! echo "$new_hostname" | grep -qE '^[a-zA-Z0-9][a-zA-Z0-9.-]{0,253}[a-zA-Z0-9]$'; then
59 | danger "无效的主机名!主机名应只包含字母、数字、点号和连字符,且长度不超过255字符"
60 | return 1
61 | fi
62 |
63 | # Update /etc/hostname (standard for most modern distributions)
64 | if [ -w /etc/hostname ]; then
65 | echo "$new_hostname" > /etc/hostname
66 | else
67 | warn "/etc/hostname 不可写,尝试其他配置路径"
68 | fi
69 |
70 | # Update /etc/hosts to ensure localhost mapping
71 | if [ -w /etc/hosts ]; then
72 | sed -i "s/127\.0\.1\.1\s\+$current_hostname/127.0.1.1\t$new_hostname/" /etc/hosts
73 | # Add entry if it doesn't exist
74 | if ! grep -q "127.0.1.1.*$new_hostname" /etc/hosts; then
75 | echo "127.0.1.1 $new_hostname" >> /etc/hosts
76 | fi
77 | else
78 | warn "/etc/hosts 不可写,可能影响主机名解析"
79 | fi
80 |
81 | # Handle distribution-specific hostname configurations
82 | # Red Hat-based systems (CentOS, RHEL, Fedora)
83 | if [ -w /etc/sysconfig/network ]; then
84 | sed -i "s/HOSTNAME=.*/HOSTNAME=$new_hostname/" /etc/sysconfig/network
85 | # Add if not present
86 | if ! grep -q "HOSTNAME=" /etc/sysconfig/network; then
87 | echo "HOSTNAME=$new_hostname" >> /etc/sysconfig/network
88 | fi
89 | fi
90 |
91 | # Slackware
92 | if [ -w /etc/HOSTNAME ]; then
93 | echo "$new_hostname" > /etc/HOSTNAME
94 | fi
95 |
96 | # Arch Linux (uses /etc/hostname, but ensure it's explicit)
97 | if [ -f /etc/arch-release ] && [ -w /etc/hostname ]; then
98 | echo "$new_hostname" > /etc/hostname
99 | fi
100 |
101 | # Gentoo
102 | if [ -w /etc/conf.d/hostname ]; then
103 | sed -i "s/hostname=.*/hostname=\"$new_hostname\"/" /etc/conf.d/hostname
104 | if ! grep -q "hostname=" /etc/conf.d/hostname; then
105 | echo "hostname=\"$new_hostname\"" >> /etc/conf.d/hostname
106 | fi
107 | fi
108 |
109 | # Apply hostname dynamically (optional, for current session)
110 | if command -v hostnamectl &>/dev/null; then
111 | hostnamectl set-hostname "$new_hostname"
112 | elif command -v hostname &>/dev/null; then
113 | hostname "$new_hostname"
114 | else
115 | warn "无法动态设置主机名,需重启以应用更改"
116 | fi
117 |
118 | success "主机名已永久更改为: $new_hostname"
119 | info "建议重启系统以确保所有服务识别新主机名"
120 | }
121 |
122 | # Main execution
123 | modify_hostname
--------------------------------------------------------------------------------
/shell_scripts/utility_tools/ports_management.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: port_management.sh
5 | # 功能: 这是一个端口管理脚本,用于管理本机的端口。
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-13
8 | # 许可证: MIT
9 |
10 | ### === 版本信息 === ###
11 | SCRIPT_VERSION="0.0.1"
12 | SCRIPT_NAME="用于管理本机的端口"
13 | SCRIPT_AUTHOR="[@Rouxyang] "
14 |
15 | echo -e "\033[33m[信息] $SCRIPT_NAME ,版本: $SCRIPT_VERSION\033[0m"
16 | echo -e "\033[33m[作者] $SCRIPT_AUTHOR\033[0m"
17 |
18 | ### === 退出状态码 === ###
19 | EXIT_SUCCESS=0
20 | EXIT_ERROR=1
21 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
22 |
23 | ### === 权限检查 === ###
24 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
25 |
26 | ### === 颜色定义 === ###
27 | RED='\033[0;31m'
28 | GREEN='\033[0;32m'
29 | YELLOW='\033[0;33m'
30 | CYAN='\033[0;36m'
31 | NC='\033[0m'
32 |
33 | ### === 彩色输出函数 === ###
34 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
35 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
36 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
37 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
38 |
39 | ### === 信号捕获 === ###
40 | cleanup() {
41 | log "INFO" "脚本被中断..."
42 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
43 | exit $EXIT_INTERRUPT
44 | }
45 | trap cleanup SIGINT SIGTERM
46 |
47 |
48 | # System info
49 | sys_id=$(cat /etc/os-release | grep ^ID= | cut -d'=' -f2 | tr -d '"')
50 |
51 | # Software dependencies
52 | software_list=("net-tools") # 示例扩展列表
53 |
54 | # 关联数组:映射软件包到检查命令,支持多命令和系统特定配置
55 | # 格式:["包名@系统"]="命令1 命令2 ..." 或 ["包名"]="命令1 命令2 ..."
56 | declare -A pkg_check_commands=(
57 | ["net-tools"]="ifconfig netstat" # 默认检查 ifconfig 或 netstat
58 | ["net-tools@alpine"]="ifconfig" # Alpine 特定的检查命令
59 | )
60 |
61 | # Install software
62 | install_software() {
63 | if [ ${#software_list[@]} -eq 0 ]; then
64 | danger "software_list 中未指定任何软件包"
65 | exit 1
66 | fi
67 |
68 | # 检查命令是否存在
69 | check_command() {
70 | local cmd="$1"
71 | command -v "$cmd" &>/dev/null
72 | }
73 |
74 | # 使用包管理器检查包是否已安装
75 | check_package_installed() {
76 | local pkg="$1"
77 | case ${sys_id} in
78 | centos|rhel|fedora|rocky|almalinux)
79 | rpm -q "$pkg" &>/dev/null
80 | ;;
81 | debian|ubuntu|linuxmint)
82 | dpkg -l "$pkg" &>/dev/null
83 | ;;
84 | arch|manjaro)
85 | pacman -Qs "$pkg" &>/dev/null
86 | ;;
87 | opensuse|suse)
88 | zypper se -i "$pkg" &>/dev/null
89 | ;;
90 | alpine)
91 | apk info "$pkg" &>/dev/null
92 | ;;
93 | openwrt)
94 | opkg status "$pkg" &>/dev/null
95 | ;;
96 | *)
97 | return 1 # 未知系统,跳过包管理器检查
98 | ;;
99 | esac
100 | }
101 |
102 | # 动态检测系统特定的包名
103 | get_system_package_name() {
104 | local pkg="$1"
105 | local sys_pkg="$pkg" # 默认使用原始包名
106 |
107 | case ${sys_id} in
108 | alpine)
109 | # Alpine 特定规则:尝试已知映射
110 | case "$pkg" in
111 | iproute2)
112 | sys_pkg="iproute" # Alpine 上 iproute2 可能是 iproute
113 | ;;
114 | *)
115 | # 使用 apk search 查找(避免每次都调用以提高性能)
116 | if apk search "$pkg" | grep -q "^${pkg}-"; then
117 | sys_pkg="$pkg"
118 | fi
119 | ;;
120 | esac
121 | ;;
122 | debian|ubuntu|linuxmint)
123 | # 使用 apt-cache search 查找
124 | if apt-cache show "$pkg" &>/dev/null; then
125 | sys_pkg="$pkg"
126 | fi
127 | ;;
128 | centos|rhel|fedora|rocky|almalinux)
129 | # 使用 dnf/yum provides 查找
130 | if check_command dnf && dnf provides "$pkg" &>/dev/null; then
131 | sys_pkg="$pkg"
132 | elif check_command yum && yum provides "$pkg" &>/dev/null; then
133 | sys_pkg="$pkg"
134 | fi
135 | ;;
136 | arch|manjaro)
137 | # 使用 pacman -Ss 查找
138 | if pacman -Ss "^${pkg}$" &>/dev/null; then
139 | sys_pkg="$pkg"
140 | fi
141 | ;;
142 | opensuse|suse)
143 | # 使用 zypper search 查找
144 | if zypper se "$pkg" &>/dev/null; then
145 | sys_pkg="$pkg"
146 | fi
147 | ;;
148 | openwrt)
149 | # 使用 opkg list 查找
150 | if opkg list | grep -q "^${pkg} -"; then
151 | sys_pkg="$pkg"
152 | fi
153 | ;;
154 | *)
155 | # 未知系统,直接使用原始包名
156 | ;;
157 | esac
158 |
159 | echo "$sys_pkg"
160 | }
161 |
162 | install_package() {
163 | local pkg="$1"
164 | # 动态获取系统特定的包名
165 | local install_pkg
166 | install_pkg=$(get_system_package_name "$pkg")
167 | # 获取检查命令,优先使用系统特定配置
168 | local check_key="${pkg}@${sys_id}"
169 | local check_cmds="${pkg_check_commands[$check_key]:-${pkg_check_commands[$pkg]:-$pkg}}"
170 |
171 | info "正在处理 $pkg (安装包名: $install_pkg)..."
172 |
173 | # 检查任意一个命令是否存在
174 | local cmd_found=0
175 | for cmd in $check_cmds; do
176 | if check_command "$cmd"; then
177 | cmd_found=1
178 | break
179 | fi
180 | done
181 |
182 | # 如果命令存在或包管理器确认已安装,则跳过安装
183 | if [ $cmd_found -eq 1 ] || check_package_installed "$install_pkg"; then
184 | success "$pkg 已安装"
185 | return 1
186 | fi
187 |
188 | info "正在安装 $install_pkg..."
189 | case ${sys_id} in
190 | centos|rhel|fedora|rocky|almalinux)
191 | if check_command dnf; then
192 | dnf -y update &>/dev/null && dnf install -y epel-release &>/dev/null
193 | dnf install -y "$install_pkg" &>/dev/null
194 | elif check_command yum; then
195 | yum -y update &>/dev/null && yum install -y epel-release &>/dev/null
196 | yum install -y "$install_pkg" &>/dev/null
197 | else
198 | danger "${sys_id} 上未找到 yum 或 dnf"
199 | return 1
200 | fi
201 | ;;
202 | debian|ubuntu|linuxmint)
203 | apt update -y &>/dev/null
204 | apt install -y "$install_pkg" &>/dev/null
205 | ;;
206 | arch|manjaro)
207 | if check_command pacman; then
208 | pacman -Syu --noconfirm &>/dev/null
209 | pacman -S --noconfirm "$install_pkg" &>/dev/null
210 | else
211 | danger "${sys_id} 上未找到 pacman"
212 | return 1
213 | fi
214 | ;;
215 | opensuse|suse)
216 | if check_command zypper; then
217 | zypper refresh &>/dev/null
218 | zypper install -y "$install_pkg" &>/dev/null
219 | else
220 | danger "${sys_id} 上未找到 zypper"
221 | return 1
222 | fi
223 | ;;
224 | alpine)
225 | if check_command apk; then
226 | apk update &>/dev/null
227 | apk add "$install_pkg" &>/dev/null
228 | else
229 | danger "${sys_id} 上未找到 apk"
230 | return 1
231 | fi
232 | ;;
233 | openwrt)
234 | if check_command opkg; then
235 | opkg update &>/dev/null
236 | opkg install "$install_pkg" &>/dev/null
237 | else
238 | danger "${sys_id} 上未找到 opkg"
239 | return 1
240 | fi
241 | ;;
242 | *)
243 | danger "未知系统: ${sys_id},请手动安装 $install_pkg"
244 | return 1
245 | ;;
246 | esac
247 |
248 | # 再次检查命令或包状态
249 | cmd_found=0
250 | for cmd in $check_cmds; do
251 | if check_command "$cmd"; then
252 | cmd_found=1
253 | break
254 | fi
255 | done
256 |
257 | if [ $cmd_found -eq 1 ] || check_package_installed "$install_pkg"; then
258 | success "$pkg 安装成功"
259 | return 0
260 | else
261 | danger "无法安装 $pkg"
262 | return 1
263 | fi
264 | }
265 | }
266 |
267 | # Manage ports
268 | manage_ports() {
269 | clear
270 | install_software
271 | while true; do
272 | info "端口管理"
273 | echo "------------------------"
274 | echo "1. 查看所有端口"
275 | echo "2. 查看指定端口"
276 | echo "3. 强制停止使用端口的程序"
277 | echo "4. 关闭指定端口"
278 | echo "0. 退出"
279 | echo "------------------------"
280 | read -p "请输入您的选择: " choice
281 |
282 | case $choice in
283 | 1)
284 | info "正在显示所有开放端口..."
285 | if command -v ss &>/dev/null; then
286 | ss -tulnape
287 | elif command -v netstat &>/dev/null; then
288 | netstat -tulnp
289 | else
290 | danger "未找到 ss 或 netstat,正在安装 net-tools..."
291 | software_list=("net-tools")
292 | install_software
293 | netstat -tulnp
294 | fi
295 | ;;
296 | 2)
297 | read -p "请输入要查看的端口号 (多个端口用逗号分隔): " ports
298 | if [ -z "$ports" ]; then
299 | danger "端口号不能为空"
300 | continue
301 | fi
302 | info "正在检查端口: $ports..."
303 | IFS=',' read -ra port_array <<< "$ports"
304 | for port in "${port_array[@]}"; do
305 | port=$(echo "$port" | tr -d '[:space:]')
306 | if [[ ! "$port" =~ ^[0-9]+$ || $port -lt 1 || $port -gt 65535 ]]; then
307 | danger "无效的端口号: $port"
308 | continue
309 | fi
310 | if command -v ss &>/dev/null; then
311 | result=$(ss -tulnape | grep ":$port " || echo "端口 $port 未被使用")
312 | if [ -n "$result" ]; then
313 | echo "$result"
314 | fi
315 | elif command -v netstat &>/dev/null; then
316 | result=$(netstat -tulnp | grep ":$port " || echo "端口 $port 未被使用")
317 | if [ -n "$result" ]; then
318 | echo "$result"
319 | fi
320 | else
321 | danger "未找到 ss 或 netstat,正在安装 net-tools..."
322 | software_list=("net-tools")
323 | install_software
324 | netstat -tulnp | grep ":$port " || echo "端口 $port 未被使用"
325 | fi
326 | done
327 | ;;
328 | 3)
329 | read -p "请输入要停止的端口号: " port
330 | if [[ ! "$port" =~ ^[0-9]+$ || $port -lt 1 || $port -gt 65535 ]]; then
331 | danger "无效的端口号"
332 | continue
333 | fi
334 | info "正在查找使用端口 $port 的程序..."
335 | pids=$(ss -tulnape | grep ":$port " | awk '{print $NF}' | grep -o '[0-9]\+')
336 | if [ -z "$pids" ]; then
337 | warn "未找到使用端口 $port 的程序"
338 | continue
339 | fi
340 | for pid in $pids; do
341 | proc_name=$(ps -p "$pid" -o comm= 2>/dev/null || echo "未知")
342 | read -p "发现进程 $proc_name (PID: $pid) 使用端口 $port,是否强制终止?(y/n): " confirm
343 | if [[ "$confirm" =~ ^[Yy]$ ]]; then
344 | kill -9 "$pid" 2>/dev/null
345 | if ! ps -p "$pid" &>/dev/null; then
346 | success "进程 $proc_name (PID: $pid) 已终止"
347 | else
348 | danger "无法终止进程 $proc_name (PID: $pid)"
349 | fi
350 | fi
351 | done
352 | ;;
353 | 4)
354 | read -p "请输入要关闭的端口号 (多个端口用逗号分隔): " ports
355 | if [ -z "$ports" ]; then
356 | danger "端口号不能为空"
357 | continue
358 | fi
359 | IFS=',' read -ra port_array <<< "$ports"
360 | firewall_tool=""
361 | if command -v ufw &>/dev/null && ufw status | grep -q "Status: active"; then
362 | firewall_tool="ufw"
363 | elif command -v firewall-cmd &>/dev/null && systemctl is-active firewalld &>/dev/null; then
364 | firewall_tool="firewalld"
365 | elif command -v iptables &>/dev/null; then
366 | firewall_tool="iptables"
367 | else
368 | warn "未找到 ufw、firewalld 或 iptables,正在安装 ufw..."
369 | software_list=("ufw")
370 | install_software
371 | ufw enable
372 | firewall_tool="ufw"
373 | fi
374 |
375 | info "使用 $firewall_tool 关闭端口..."
376 | for port in "${port_array[@]}"; do
377 | port=$(echo "$port" | tr -d '[:space:]')
378 | if [[ ! "$port" =~ ^[0-9]+$ || $port -lt 1 || $port -gt 65535 ]]; then
379 | danger "无效的端口号: $port"
380 | continue
381 | fi
382 | case $firewall_tool in
383 | ufw)
384 | ufw deny "$port/tcp" >/dev/null
385 | ufw deny "$port/udp" >/dev/null
386 | success "端口 $port 已关闭 (TCP/UDP)"
387 | ;;
388 | firewalld)
389 | firewall-cmd --permanent --add-port="$port/tcp" --add-port="$port/udp" >/dev/null
390 | firewall-cmd --reload >/dev/null
391 | success "端口 $port 已关闭 (TCP/UDP)"
392 | ;;
393 | iptables)
394 | iptables -A INPUT -p tcp --dport "$port" -j DROP
395 | iptables -A INPUT -p udp --dport "$port" -j DROP
396 | success "端口 $port 已关闭 (TCP/UDP)"
397 | if command -v iptables-save &>/dev/null; then
398 | iptables-save > /etc/iptables.rules 2>/dev/null
399 | success "iptables 规则已保存"
400 | fi
401 | ;;
402 | esac
403 | done
404 | ;;
405 | 0)
406 | break
407 | ;;
408 | *)
409 | danger "无效的选择"
410 | ;;
411 | esac
412 | echo ""
413 | info "按回车继续..."
414 | read -r
415 | done
416 | }
417 |
418 | # Main execution
419 | manage_ports
--------------------------------------------------------------------------------
/shell_scripts/utility_tools/ssh_management.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ### === 脚本描述 === ###
4 | # 脚本名称: ssh_management.sh
5 | # 功能: 这是一个ssh管理脚本
6 | # 作者: rouxyang
7 | # 创建日期: 2025-04-13
8 |
9 | ### === 版本信息 === ###
10 | SCRIPT_VERSION="0.0.1"
11 | echo -e "\033[32m[信息] 脚本版本: $SCRIPT_VERSION\033[0m"
12 |
13 | ### === 退出状态码 === ###
14 | EXIT_SUCCESS=0
15 | EXIT_ERROR=1
16 | EXIT_INTERRUPT=130 # Ctrl+C 退出码
17 |
18 | ### === 权限检查 === ###
19 | [[ $EUID -ne 0 ]] && echo -e "\033[31m[错误] 请以root用户或sudo运行此脚本!\033[0m" && exit 1
20 |
21 | ### === 颜色定义 === ###
22 | RED='\033[0;31m'
23 | GREEN='\033[0;32m'
24 | YELLOW='\033[0;33m'
25 | CYAN='\033[0;36m'
26 | NC='\033[0m'
27 |
28 | ### === 彩色输出函数 === ###
29 | success() { printf "${GREEN}%b${NC} ${@:2}\n" "$1"; }
30 | info() { printf "${CYAN}%b${NC} ${@:2}\n" "$1"; }
31 | danger() { printf "\n${RED}[错误] %b${NC}\n" "$@"; }
32 | warn() { printf "${YELLOW}[警告] %b${NC}\n" "$@"; }
33 |
34 |
35 | ### === 信号捕获 === ###
36 | cleanup() {
37 | log "INFO" "脚本被中断..."
38 | echo -e "${YELLOW}[警告] 脚本已退出!${NC}"
39 | exit $EXIT_INTERRUPT
40 | }
41 | trap cleanup SIGINT SIGTERM
42 |
43 | ### === 日志函数 === ###
44 | log() {
45 | local level="$1"
46 | local message="$2"
47 | local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
48 | local log_file="/var/log/ssh_management.log"
49 | echo "[$timestamp] [$level] $message" >> "$log_file" 2>/dev/null || {
50 | echo "[$timestamp] [ERROR] 无法写入日志文件: $log_file" >&2
51 | }
52 | }
53 |
54 | ### === 检测依赖工具 === ###
55 | check_dependencies() {
56 | local missing_deps=()
57 | local commands=("ss" "awk" "sed" "grep")
58 | for cmd in "${commands[@]}"; do
59 | if ! command -v "$cmd" >/dev/null 2>&1; then
60 | missing_deps+=("$cmd")
61 | fi
62 | done
63 | if [ ${#missing_deps[@]} -ne 0 ]; then
64 | danger "缺少以下依赖工具: ${missing_deps[*]}"
65 | log "ERROR" "缺少依赖: ${missing_deps[*]}"
66 | warn "请安装缺失工具,例如:"
67 | warn " Ubuntu/Debian: sudo apt install iproute2 gawk sed grep"
68 | warn " CentOS/RHEL: sudo yum install iproute2 gawk sed grep"
69 | exit $EXIT_ERROR
70 | fi
71 | }
72 |
73 | ### === 检测防火墙工具 === ###
74 | detect_firewall() {
75 | if command -v ufw >/dev/null 2>&1; then
76 | echo "ufw"
77 | elif command -v firewall-cmd >/dev/null 2>&1; then
78 | echo "firewalld"
79 | elif command -v iptables >/dev/null 2>&1; then
80 | echo "iptables"
81 | elif command -v nft >/dev/null 2>&1; then
82 | echo "nftables"
83 | else
84 | echo "none"
85 | fi
86 | }
87 |
88 | ### === 重启 SSH 服务 === ###
89 | restart_ssh_service() {
90 | local ssh_service
91 | if systemctl is-active sshd >/dev/null 2>&1; then
92 | ssh_service="sshd"
93 | elif systemctl is-active ssh >/dev/null 2>&1; then
94 | ssh_service="ssh"
95 | else
96 | danger "无法检测 SSH 服务"
97 | log "ERROR" "未找到 SSH 服务"
98 | return 1
99 | fi
100 |
101 | if command -v systemctl >/dev/null 2>&1; then
102 | systemctl restart "$ssh_service" || {
103 | danger "重启 $ssh_service 失败"
104 | log "ERROR" "重启 $ssh_service 失败"
105 | return 1
106 | }
107 | elif command -v service >/dev/null 2>&1; then
108 | service "$ssh_service" restart || {
109 | danger "重启 $ssh_service 失败"
110 | log "ERROR" "重启 $ssh_service 失败"
111 | return 1
112 | }
113 | else
114 | warn "未检测到支持的服务管理器,请手动重启 SSH"
115 | log "WARN" "未找到服务管理器"
116 | return 1
117 | fi
118 | success "SSH 服务 ($ssh_service) 已重启"
119 | log "INFO" "SSH 服务 ($ssh_service) 重启成功"
120 | }
121 |
122 | ### === 备份 SSH 配置 === ###
123 | backup_ssh_config() {
124 | local timestamp=$(date +%Y%m%d_%H%M%S)
125 | local backup_file="/etc/ssh/sshd_config.bak_$timestamp"
126 | if [ -f /etc/ssh/sshd_config ]; then
127 | cp /etc/ssh/sshd_config "$backup_file" || {
128 | danger "备份 SSH 配置失败"
129 | log "ERROR" "备份 SSH 配置失败: $backup_file"
130 | return 1
131 | }
132 | find /etc/ssh -name 'sshd_config.bak_*' -type f | sort -r | tail -n +6 | xargs -I {} rm -f {} || {
133 | warn "清理旧备份文件失败"
134 | log "WARN" "清理旧备份文件失败"
135 | }
136 | success "已生成备份文件: $backup_file"
137 | log "INFO" "SSH 配置备份: $backup_file"
138 | return 0
139 | else
140 | danger "SSH 配置文件不存在"
141 | log "ERROR" "SSH 配置文件 /etc/ssh/sshd_config 不存在"
142 | return 1
143 | fi
144 | }
145 |
146 | ### === 验证 SSH 配置 === ###
147 | validate_ssh_config() {
148 | if sshd -t >/dev/null 2>&1; then
149 | success "SSH 配置验证通过"
150 | log "INFO" "SSH 配置验证通过"
151 | return 0
152 | else
153 | local error_output
154 | error_output=$(sshd -t 2>&1)
155 | danger "SSH 配置验证失败: $error_output"
156 | log "ERROR" "SSH 配置验证失败: $error_output"
157 | return 1
158 | fi
159 | }
160 |
161 | ### === 回滚 SSH 配置 === ###
162 | rollback_ssh_config() {
163 | local latest_backup
164 | latest_backup=$(find /etc/ssh -name 'sshd_config.bak_*' -type f | sort -r | head -n 1)
165 | if [ -z "$latest_backup" ]; then
166 | danger "未找到可用的备份文件,无法回滚"
167 | log "ERROR" "未找到备份文件"
168 | return 1
169 | fi
170 | if cp "$latest_backup" /etc/ssh/sshd_config; then
171 | success "已回滚到备份: $latest_backup"
172 | log "INFO" "SSH 配置回滚: $latest_backup"
173 | if restart_ssh_service; then
174 | success "SSH 服务已重启以应用回滚"
175 | else
176 | warn "回滚成功,但重启 SSH 服务失败"
177 | log "WARN" "回滚后重启 SSH 服务失败"
178 | fi
179 | return 0
180 | else
181 | danger "回滚 SSH 配置失败"
182 | log "ERROR" "回滚 SSH 配置失败: $latest_backup"
183 | return 1
184 | fi
185 | }
186 |
187 | ### === 修改 SSH 配置 === ###
188 | modify_ssh_config() {
189 | local pattern="$1"
190 | local replacement="$2"
191 | backup_ssh_config || return 1
192 | if sed -i.bak -E "s|$pattern|$replacement|" /etc/ssh/sshd_config; then
193 | if validate_ssh_config; then
194 | if restart_ssh_service; then
195 | success "SSH 配置已更新"
196 | log "INFO" "SSH 配置修改: $pattern -> $replacement"
197 | else
198 | danger "SSH 服务重启失败,尝试回滚"
199 | log "ERROR" "SSH 服务重启失败"
200 | rollback_ssh_config || danger "回滚也失败,请手动检查 /etc/ssh/sshd_config"
201 | return 1
202 | fi
203 | else
204 | danger "SSH 配置无效,执行回滚"
205 | rollback_ssh_config || danger "回滚失败,请手动恢复"
206 | return 1
207 | fi
208 | else
209 | danger "修改 SSH 配置失败"
210 | log "ERROR" "修改 SSH 配置失败: $pattern -> $replacement"
211 | return 1
212 | fi
213 | }
214 |
215 | ### === 检查 SSH 状态 === ###
216 | check_ssh_status() {
217 | local port
218 | local auth
219 | local connections
220 | port=$(grep '^Port ' /etc/ssh/sshd_config | awk '{print $2}' || echo "22")
221 | auth=$(grep '^PasswordAuthentication ' /etc/ssh/sshd_config | awk '{print $2}' || echo "未知")
222 | connections=$(ss -tun | grep ":$port" | wc -l || echo "未知")
223 | info "SSH 状态:"
224 | info " 端口: $port"
225 | info " 密码认证: $auth"
226 | info " 活跃连接: $connections"
227 | log "INFO" "SSH 状态检查:端口=$port, 密码认证=$auth, 活跃连接=$connections"
228 | }
229 |
230 | ### === 修改端口 === ###
231 | change_port() {
232 | local port
233 | read -p "请输入新的 SSH 端口号(1-65535): " port
234 | if [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ]; then
235 | if ss -tuln | grep ":$port" >/dev/null; then
236 | danger "端口 $port 已被占用"
237 | log "ERROR" "端口 $port 已被占用"
238 | return 1
239 | fi
240 | modify_ssh_config "^#?Port .*" "Port $port" || return 1
241 | success "SSH 端口已更改为 $port"
242 | log "INFO" "SSH 端口更改为 $port"
243 | else
244 | danger "无效的端口号"
245 | log "ERROR" "无效的端口号: $port"
246 | return 1
247 | fi
248 | }
249 |
250 | ### === 添加公钥 === ###
251 | add_key() {
252 | echo "请粘贴完整的公钥文本(例如 ssh-rsa AAA...),然后按 Enter 确认(或按 Ctrl+C 取消):"
253 | local public_key
254 | read -r public_key
255 | if [ -z "$public_key" ]; then
256 | danger "未输入公钥,添加失败"
257 | log "ERROR" "未输入公钥"
258 | return 1
259 | fi
260 | if [[ "$public_key" =~ ^ssh-(rsa|ed25519|ecdsa)\ [A-Za-z0-9+/=]+ ]]; then
261 | local auth_file="/root/.ssh/authorized_keys"
262 | mkdir -p /root/.ssh && chmod 700 /root/.ssh || {
263 | danger "创建 /root/.ssh 目录失败,添加失败"
264 | log "ERROR" "创建 /root/.ssh 目录失败"
265 | return 1
266 | }
267 | if [ -f "$auth_file" ] && grep -Fx "$public_key" "$auth_file" >/dev/null 2>&1; then
268 | warn "公钥已存在,无需重复添加"
269 | log "WARN" "公钥已存在: ${public_key:0:50}..."
270 | return 0
271 | fi
272 | touch "$auth_file" && chmod 600 "$auth_file" || {
273 | danger "设置 $auth_file 权限失败,添加失败"
274 | log "ERROR" "设置 $auth_file 权限失败"
275 | return 1
276 | }
277 | echo "$public_key" >> "$auth_file" || {
278 | danger "添加公钥到 $auth_file 失败"
279 | log "ERROR" "添加公钥失败: ${public_key:0:50}..."
280 | return 1
281 | }
282 | success "SSH 公钥添加成功"
283 | log "INFO" "添加 SSH 公钥: ${public_key:0:50}..."
284 | return 0
285 | else
286 | danger "无效的公钥格式,添加失败"
287 | log "ERROR" "无效的公钥格式: ${public_key:0:50}..."
288 | return 1
289 | fi
290 | }
291 |
292 | # 检查防火墙状态的函数
293 | check_firewall_status() {
294 | local firewall
295 | firewall=$(detect_firewall) # 假设 detect_firewall 函数已定义
296 |
297 | case $firewall in
298 | ufw)
299 | if ufw status | grep -q "Status: active"; then
300 | success "UFW 防火墙已启用"
301 | return 0
302 | else
303 | warn "UFW 防火墙未启用"
304 | return 1
305 | fi
306 | ;;
307 | firewalld)
308 | if systemctl is-active firewalld >/dev/null 2>&1; then
309 | success "Firewalld 防火墙已启用"
310 | return 0
311 | else
312 | warn "Firewalld 防火墙未启用"
313 | return 1
314 | fi
315 | ;;
316 | iptables)
317 | if iptables -L >/dev/null 2>&1; then
318 | success "iptables 已安装且可用"
319 | return 0
320 | else
321 | danger "iptables 未安装或不可用"
322 | return 1
323 | fi
324 | ;;
325 | nftables)
326 | if nft list tables >/dev/null 2>&1; then
327 | success "nftables 已安装且可用"
328 | return 0
329 | else
330 | danger "nftables 未安装或不可用"
331 | return 1
332 | fi
333 | ;;
334 | *)
335 | danger "未检测到支持的防火墙(ufw、firewalld、iptables 或 nftables)"
336 | return 1
337 | ;;
338 | esac
339 | }
340 |
341 | # 限制 SSH IP 的函数
342 | restrict_ip() {
343 | # 先检查防火墙状态
344 | check_firewall_status
345 | if [ $? -ne 0 ]; then
346 | danger "防火墙未启用或不可用,无法设置 IP 限制"
347 | log "ERROR" "防火墙未启用或不可用,终止执行"
348 | return 1
349 | fi
350 |
351 | local ip
352 | read -p "请输入允许访问 SSH 的 IP 地址(例如 192.168.1.100): " ip
353 | if [[ "$ip" =~ ^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$ ]]; then
354 | for i in {1..4}; do
355 | if [ "${BASH_REMATCH[$i]}" -gt 255 ]; then
356 | danger "无效的 IP 地址: $ip"
357 | log "ERROR" "无效的 IP 地址: $ip"
358 | return 1
359 | fi
360 | done
361 | local ssh_port
362 | ssh_port=$(grep '^Port ' /etc/ssh/sshd_config | awk '{print $2}' || echo "22")
363 | local firewall
364 | firewall=$(detect_firewall)
365 | local firewall_active=0
366 |
367 | # 再次确认防火墙状态(与 check_firewall_status 保持一致)
368 | case $firewall in
369 | ufw)
370 | if ufw status | grep -q "Status: active"; then
371 | firewall_active=1
372 | else
373 | warn "UFW 防火墙未启用"
374 | read -p "是否启用 UFW?(y/n): " enable_ufw
375 | if [[ "$enable_ufw" =~ ^[Yy]$ ]]; then
376 | ufw enable || {
377 | danger "启用 UFW 失败"
378 | log "ERROR" "启用 UFW 失败"
379 | return 1
380 | }
381 | firewall_active=1
382 | success "UFW 已启用"
383 | log "INFO" "UFW 防火墙已启用"
384 | else
385 | danger "UFW 未启用,无法设置 IP 限制"
386 | log "ERROR" "UFW 未启用,用户选择不启用"
387 | return 1
388 | fi
389 | fi
390 | ;;
391 | firewalld)
392 | if systemctl is-active firewalld >/dev/null 2>&1; then
393 | firewall_active=1
394 | else
395 | warn "Firewalld 防火墙未启用"
396 | read -p "是否启用 Firewalld?(y/n): " enable_firewalld
397 | if [[ "$enable_firewalld" =~ ^[Yy]$ ]]; then
398 | systemctl start firewalld || {
399 | danger "启用 Firewalld 失败"
400 | log "ERROR" "启用 Firewalld 失败"
401 | return 1
402 | }
403 | firewall_active=1
404 | success "Firewalld 已启用"
405 | log "INFO" "Firewalld 防火墙已启用"
406 | else
407 | danger "Firewalld 未启用,无法设置 IP 限制"
408 | log "ERROR" "Firewalld 未启用,用户选择不启用"
409 | return 1
410 | fi
411 | fi
412 | ;;
413 | iptables)
414 | # iptables is always "active" if installed (no daemon)
415 | firewall_active=1
416 | warn "注意:iptables 规则不会在重启后自动持久化,请手动保存(例如使用 iptables-save)"
417 | log "WARN" "iptables 规则需手动持久化"
418 | ;;
419 | nftables)
420 | # nftables is always "active" if installed (no daemon)
421 | firewall_active=1
422 | warn "注意:nftables 规则不会在重启后自动持久化,请手动保存(例如使用 nft list ruleset)"
423 | log "WARN" "nftables 规则需手动持久化"
424 | ;;
425 | *)
426 | danger "未检测到支持的防火墙(ufw、firewalld、iptables 或 nftables)"
427 | log "ERROR" "未检测到支持的防火墙"
428 | return 1
429 | ;;
430 | esac
431 |
432 | # Apply firewall rules if active
433 | if [ "$firewall_active" -eq 1 ]; then
434 | case $firewall in
435 | ufw)
436 | ufw allow from "$ip" to any port "$ssh_port" proto tcp || {
437 | danger "设置 ufw 规则失败"
438 | log "ERROR" "设置 ufw 规则失败: IP=$ip, 端口=$ssh_port"
439 | return 1
440 | }
441 | ufw reload || {
442 | danger "重载 ufw 失败"
443 | log "ERROR" "重载 ufw 失败"
444 | return 1
445 | }
446 | success "SSH 限制为仅 $ip 可访问(使用 ufw,端口 $ssh_port)"
447 | log "INFO" "限制 SSH 访问: IP=$ip, 端口=$ssh_port, 防火墙=ufw"
448 | ;;
449 | firewalld)
450 | firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=$ip port port=$ssh_port protocol=tcp accept" || {
451 | danger "设置 firewalld 规则失败"
452 | log "ERROR" "设置 firewalld 规则失败: IP=$ip, 端口=$ssh_port"
453 | return 1
454 | }
455 | firewall-cmd --reload || {
456 | danger "重载 firewalld 失败"
457 | log "ERROR" "重载 firewalld 失败"
458 | return 1
459 | }
460 | success "SSH 限制为仅 $ip 可访问(使用 firewalld,端口 $ssh_port)"
461 | log "INFO" "限制 SSH 访问: IP=$ip, 端口=$ssh_port, 防火墙=firewalld"
462 | ;;
463 | iptables)
464 | iptables -A INPUT -p tcp --dport "$ssh_port" -s "$ip" -j ACCEPT || {
465 | danger "设置 iptables 规则失败"
466 | log "ERROR" "设置 iptables 规则失败: IP=$ip, 端口=$ssh_port"
467 | return 1
468 | }
469 | iptables -A INPUT -p tcp --dport "$ssh_port" -j DROP || {
470 | danger "设置 iptables 规则失败"
471 | log "ERROR" "设置 iptables 规则失败: IP=$ip, 端口=$ssh_port"
472 | return 1
473 | }
474 | success "SSH 限制为仅 $ip 可访问(使用 iptables,端口 $ssh_port)"
475 | log "INFO" "限制 SSH 访问: IP=$ip, 端口=$ssh_port, 防火墙=iptables"
476 | ;;
477 | nftables)
478 | nft add table inet ssh_filter || {
479 | danger "创建 nftables 表失败"
480 | log "ERROR" "创建 nftables 表失败: IP=$ip, 端口=$ssh_port"
481 | return 1
482 | }
483 | nft add chain inet ssh_filter input \{ type filter hook input priority 0 \; policy drop \; \} || {
484 | danger "创建 nftables 链失败"
485 | log "ERROR" "创建 nftables 链失败: IP=$ip, 端口=$ssh_port"
486 | return 1
487 | }
488 | nft add rule inet ssh_filter input ip saddr "$ip" tcp dport "$ssh_port" accept || {
489 | danger "设置 nftables 规则失败"
490 | log "ERROR" "设置 nftables 规则失败: IP=$ip, 端口=$ssh_port"
491 | return 1
492 | }
493 | success "SSH 限制为仅 $ip 可访问(使用 nftables,端口 $ssh_port)"
494 | log "INFO" "限制 SSH 访问: IP=$ip, 端口=$ssh_port, 防火墙=nftables"
495 | ;;
496 | esac
497 | else
498 | danger "防火墙未启用,无法设置 IP 限制"
499 | log "ERROR" "防火墙未启用,无法设置 IP 限制: $firewall"
500 | return 1
501 | fi
502 | else
503 | danger "无效的 IP 地址格式"
504 | log "ERROR" "无效的 IP 地址格式: $ip"
505 | return 1
506 | fi
507 | }
508 |
509 | ### === 禁用密码登录 === ###
510 | disable_password() {
511 | modify_ssh_config "^#?PasswordAuthentication .*" "PasswordAuthentication no" || return 1
512 | success "密码登录已禁用"
513 | log "INFO" "禁用 SSH 密码登录"
514 | }
515 |
516 | ### === 启用密码登录 === ###
517 | enable_password() {
518 | modify_ssh_config "^#?PasswordAuthentication .*" "PasswordAuthentication yes" || return 1
519 | success "密码登录已启用"
520 | log "INFO" "启用 SSH 密码登录"
521 | }
522 |
523 | ### === 优化 SSH 速度 === ###
524 | optimize_ssh_speed() {
525 | backup_ssh_config || return 1
526 | {
527 | echo 'Ciphers aes256-ctr,aes192-ctr,aes128-ctr'
528 | echo 'TCPKeepAlive yes'
529 | echo 'LoginGraceTime 30'
530 | } >> /etc/ssh/sshd_config || {
531 | danger "优化 SSH 配置失败"
532 | log "ERROR" "优化 SSH 配置失败"
533 | return 1
534 | }
535 | if validate_ssh_config; then
536 | restart_ssh_service || return 1
537 | success "SSH 连接速度已优化"
538 | log "INFO" "优化 SSH 连接速度"
539 | else
540 | danger "SSH 配置无效,执行回滚"
541 | rollback_ssh_config || danger "回滚失败,请手动恢复"
542 | return 1
543 | fi
544 | }
545 |
546 | ### === 一键优化安全性 === ###
547 | secure_ssh() {
548 | backup_ssh_config || return 1
549 | sed -i.bak -E 's|^#?PasswordAuthentication .*|PasswordAuthentication no|' /etc/ssh/sshd_config &&
550 | sed -i.bak -E 's|^#?PermitEmptyPasswords .*|PermitEmptyPasswords no|' /etc/ssh/sshd_config &&
551 | echo 'MaxAuthTries 3' >> /etc/ssh/sshd_config &&
552 | echo 'Ciphers aes256-ctr,aes192-ctr,aes128-ctr' >> /etc/ssh/sshd_config || {
553 | danger "优化 SSH 安全性失败"
554 | log "ERROR" "优化 SSH 安全性失败"
555 | return 1
556 | }
557 | if validate_ssh_config; then
558 | restart_ssh_service || return 1
559 | success "SSH 安全性已优化"
560 | log "INFO" "一键优化 SSH 安全性"
561 | else
562 | danger "SSH 配置无效,执行回滚"
563 | rollback_ssh_config || danger "回滚失败,请手动恢复"
564 | return 1
565 | fi
566 | }
567 |
568 | ### === 主菜单 === ###
569 | build_command() {
570 | echo "请根据以下选项输入对应的数字来执行操作:"
571 | echo "1 - 修改 SSH 端口"
572 | echo "2 - 添加 SSH 公钥"
573 | echo "3 - 限制 SSH 的 IP 访问"
574 | echo "4 - 禁用 SSH 密码登录"
575 | echo "5 - 启用 SSH 密码登录"
576 | echo "6 - 优化 SSH 连接速度"
577 | echo "7 - 一键优化 SSH 安全性"
578 | echo "8 - 检查 SSH 状态"
579 | echo "9 - 退出"
580 | local choice
581 | read -p "请输入选择 (1-9): " choice
582 | case $choice in
583 | 1) change_port ;;
584 | 2) add_key ;;
585 | 3) restrict_ip ;;
586 | 4) disable_password ;;
587 | 5) enable_password ;;
588 | 6) optimize_ssh_speed ;;
589 | 7) secure_ssh ;;
590 | 8) check_ssh_status ;;
591 | 9) success "退出脚本"; exit $EXIT_SUCCESS ;;
592 | *) danger "无效选择,请输入 1-9"; build_command ;;
593 | esac
594 | }
595 |
596 | ### === 主函数入口 === ###
597 | main() {
598 | log "INFO" "脚本启动: 本地执行"
599 | check_dependencies
600 | if ! whoami >/dev/null; then
601 | danger "本地命令测试失败,请检查环境"
602 | log "ERROR" "本地命令测试失败"
603 | exit $EXIT_ERROR
604 | fi
605 | build_command
606 | }
607 |
608 | main
--------------------------------------------------------------------------------