Shell脚本:模块引用

Shell脚本:模块引用

目录

  1. 引言
  2. Shell脚本模块化的重要性
  3. 基本的模块引用方法
    3.1 使用source命令
    3.2 使用点号(.)操作符
  4. 创建和组织模块
    4.1 函数模块
    4.2 变量模块
    4.3 常量模块
  5. 高级模块引用技巧
    5.1 相对路径和绝对路径
    5.2 动态模块加载
    5.3 条件模块加载
  6. 模块化最佳实践
    6.1 命名约定
    6.2 文档和注释
    6.3 版本控制
  7. 常见问题和解决方案
    7.1 循环依赖
    7.2 命名冲突
    7.3 性能考虑
  8. 实战项目:构建模块化的Shell应用
  9. 总结

1. 引言

在Shell脚本编程中,随着项目规模的增长,代码的组织和管理变得越来越重要。模块化编程是一种强大的技术,它允许我们将大型、复杂的脚本拆分成更小、更易于管理的部分。本文将深入探讨Shell脚本中的模块引用技术,帮助您编写更清晰、更高效的代码。

2. Shell脚本模块化的重要性

模块化编程在Shell脚本开发中具有多重重要性:

  1. 代码复用:通过将常用功能封装到模块中,我们可以在多个脚本中重复使用这些功能,而无需复制粘贴代码。
  2. 可维护性:将大型脚本分解成小型、独立的模块,使得代码更容易理解和维护。
  3. 协作开发:模块化使得团队成员可以并行工作在不同的模块上,提高开发效率。
  4. 测试性:独立的模块更容易进行单元测试,提高代码质量。
  5. 灵活性:模块化设计允许更容易地替换或升级特定功能,而不影响整个系统。

接下来,我们将通过一系列实例来探索如何在Shell脚本中实现和利用模块化。

3. 基本的模块引用方法

在Shell脚本中,有两种主要的方法来引用外部模块:使用source命令和使用点号(.)操作符。这两种方法本质上是等价的,选择哪一种主要取决于个人偏好和可读性考虑。

3.1 使用source命令

source命令是引用外部Shell脚本的常用方法。它会在当前Shell环境中执行指定的脚本,使得被引用脚本中定义的所有变量和函数在当前脚本中可用。

示例1:基本的source使用

假设我们有一个名为math_functions.sh的模块,其中定义了一些数学函数:

# math_functions.sh
#!/bin/bashfunction add() {echo $(($1 + $2))
}function multiply() {echo $(($1 * $2))
}

现在,我们可以在主脚本中使用source命令来引用这个模块:

#!/bin/bashsource ./math_functions.shresult_add=$(add 5 3)
result_multiply=$(multiply 4 6)echo "5 + 3 = $result_add"
echo "4 * 6 = $result_multiply"

输出:

5 + 3 = 8
4 * 6 = 24

3.2 使用点号(.)操作符

点号操作符的功能与source命令相同,它是一个更简洁的替代方案。

示例2:使用点号引用模块

我们可以修改上面的主脚本,使用点号来引用math_functions.sh

#!/bin/bash. ./math_functions.shresult_add=$(add 10 7)
result_multiply=$(multiply 3 9)echo "10 + 7 = $result_add"
echo "3 * 9 = $result_multiply"

输出:

10 + 7 = 17
3 * 9 = 27

这两种方法在功能上是等价的,选择哪一种主要取决于个人偏好和脚本的可读性。

4. 创建和组织模块

有效的模块化不仅仅是关于如何引用模块,更重要的是如何创建和组织这些模块。让我们探讨几种常见的模块类型及其组织方式。

4.1 函数模块

函数模块是最常见的模块类型,它们包含了可重用的函数定义。

示例3:创建字符串处理函数模块

# string_utils.sh
#!/bin/bashfunction to_uppercase() {echo "$1" | tr '[:lower:]' '[:upper:]'
}function to_lowercase() {echo "$1" | tr '[:upper:]' '[:lower:]'
}function reverse_string() {echo "$1" | rev
}

使用这个模块:

#!/bin/bashsource ./string_utils.shoriginal="Hello, World!"
upper=$(to_uppercase "$original")
lower=$(to_lowercase "$original")
reversed=$(reverse_string "$original")echo "Original: $original"
echo "Uppercase: $upper"
echo "Lowercase: $lower"
echo "Reversed: $reversed"

输出:

Original: Hello, World!
Uppercase: HELLO, WORLD!
Lowercase: hello, world!
Reversed: !dlroW ,olleH

4.2 变量模块

变量模块用于存储和共享配置信息或常用的数据结构。

示例4:创建配置变量模块

# config.sh
#!/bin/bash# Database configuration
DB_HOST="localhost"
DB_PORT=3306
DB_USER="admin"
DB_PASS="secret"# API endpoints
API_BASE_URL="https://api.example.com"
API_VERSION="v1"# Logging
LOG_LEVEL="INFO"
LOG_FILE="/var/log/myapp.log"

使用配置模块:

#!/bin/bashsource ./config.shecho "Connecting to database at ${DB_HOST}:${DB_PORT}"
echo "API URL: ${API_BASE_URL}/${API_VERSION}"
echo "Logging to ${LOG_FILE} with level ${LOG_LEVEL}"

输出:

Connecting to database at localhost:3306
API URL: https://api.example.com/v1
Logging to /var/log/myapp.log with level INFO

4.3 常量模块

常量模块用于定义在整个应用中保持不变的值。

示例5:创建常量模块

# constants.sh
#!/bin/bashreadonly MAX_RETRIES=3
readonly TIMEOUT_SECONDS=30
readonly ERROR_CODE_SUCCESS=0
readonly ERROR_CODE_FAILURE=1

使用常量模块:

#!/bin/bashsource ./constants.shattempt=1
while [ $attempt -le $MAX_RETRIES ]; doecho "Attempt $attempt of $MAX_RETRIES"# 模拟某些操作sleep 1attempt=$((attempt + 1))
doneif [ $attempt -gt $MAX_RETRIES ]; thenecho "Operation failed after $MAX_RETRIES attempts"exit $ERROR_CODE_FAILURE
elseecho "Operation succeeded"exit $ERROR_CODE_SUCCESS
fi

输出:

Attempt 1 of 3
Attempt 2 of 3
Attempt 3 of 3
Operation failed after 3 attempts

通过这种方式组织模块,我们可以使主脚本更加清晰,同时提高代码的可维护性和可重用性。

5. 高级模块引用技巧

在实际的Shell脚本开发中,我们经常需要处理更复杂的模块引用场景。本节将介绍一些高级技巧,帮助您更灵活地管理和使用模块。

5.1 相对路径和绝对路径

在引用模块时,我们可以使用相对路径或绝对路径。选择哪种方式取决于您的项目结构和脚本的预期用途。

示例6:使用相对路径和绝对路径

假设我们有以下项目结构:

/home/user/project/
├── main.sh
├── lib/
│   ├── math.sh
│   └── string.sh
└── config/└── settings.sh

main.sh中,我们可以这样引用模块:

#!/bin/bash# 使用相对路径
source ./lib/math.sh
source ./lib/string.sh# 使用绝对路径
source /home/user/project/config/settings.sh# 使用脚本所在目录的相对路径
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$SCRIPT_DIR/lib/math.sh"

5.2 动态模块加载

有时,我们可能需要根据运行时的条件来决定加载哪些模块。这可以通过使用变量来实现动态模块加载。

示例7:动态模块加载

#!/bin/bashMODULE_PATH="./modules"
MODULES=("math" "string" "file")for module in "${MODULES[@]}"; doif [ -f "$MODULE_PATH/${module}.sh" ]; thensource "$MODULE_PATH/${module}.sh"echo "Loaded module: $module"elseecho "Warning: Module $module not found"fi
done# 使用加载的模块
if type add &>/dev/null; thenresult=$(add 5 3)echo "5 + 3 = $result"
elseecho "Math module not loaded"
fi

这个脚本会尝试加载modules目录下的所有指定模块,并在成功加载后使用其中的函数。

5.3 条件模块加载

在某些情况下,我们可能只想在特定条件下加载某些模块。这可以通过条件语句来实现。

示例8:条件模块加载

#!/bin/bashENABLE_ADVANCED_FEATURES=truesource ./basic_functions.shif [ "$ENABLE_ADVANCED_FEATURES" = true ]; thensource ./advanced_functions.shecho "Advanced features enabled"
elseecho "Running with basic features only"
fi# 使用函数
basic_function
if type advanced_function &>/dev/null; thenadvanced_function
fi

这个脚本根据ENABLE_ADVANCED_FEATURES变量的值来决定是否加载高级功能模块。

6. 模块化最佳实践

为了充分发挥模块化的优势,遵循一些最佳实践是非常重要的。这些实践可以帮助您创建更易于维护和使用的模块。

6.1 命名约定

采用一致的命名约定可以大大提高代码的可读性和可维护性。

示例9:模块和函数命名约定

# 文件名:string_utils.sh# 前缀函数名以避免命名冲突
string_to_uppercase() {echo "${1^^}"
}string_to_lowercase() {echo "${1,,}"
}string_capitalize() {echo "${1^}"
}

在主脚本中使用:

#!/bin/bashsource ./string_utils.shtext="hello WORLD"
echo "Original: $text"
echo "Uppercase: $(string_to_uppercase "$text")"
echo "Lowercase: $(string_to_lowercase "$text")"
echo "Capitalized: $(string_capitalize "$text")"

输出:

Original: hello WORLD
Uppercase: HELLO WORLD
Lowercase: hello world
Capitalized: Hello WORLD

6.2 文档和注释

良好的文档和注释可以帮助其他开发者(包括未来的你)理解和使用你的模块。

示例10:模块文档和函数注释

#!/bin/bash
# File: math_advanced.sh
# Description: Advanced mathematical operations for shell scripts
# Author: Your Name
# Date: 2024-10-18# Calculate the factorial of a number
# Args:
#   $1 - The number to calculate factorial for
# Returns:
#   The factorial of the input number
factorial() {local num=$1local result=1for ((i=2; i<=num; i++)); doresult=$((result * i))doneecho $result
}# Calculate the nth Fibonacci number
# Args:
#   $1 - The position in the Fibonacci sequence
# Returns:
#   The Fibonacci number at the specified position
fibonacci() {local n=$1if [ $n -le 1 ]; thenecho $nelselocal a=0local b=1for ((i=2; i<=n; i++)); dolocal temp=$((a + b))a=$bb=$tempdoneecho $bfi
}

6.3 版本控制

对模块进行版本控制可以帮助管理依赖关系和兼容:

#!/bin/bash
# File: math_advanced.sh
# Description: Advanced mathematical operations for shell scripts
# Author: Your Name
# Date: 2024-10-18# Calculate the factorial of a number
# Args:
#   $1 - The number to calculate factorial for
# Returns:
#   The factorial of the input number
factorial() {local n=$1if ((n <= 1)); thenecho 1elseecho $((n * $(factorial $((n - 1)))))fi
}# Calculate the nth Fibonacci number
# Args:
#   $1 - The position in the Fibonacci sequence
# Returns:
#   The nth Fibonacci number
fibonacci() {local n=$1if ((n <= 1)); thenecho $nelseecho $(($(fibonacci $((n - 1))) + $(fibonacci $((n - 2)))))fi
}

使用这个模块:

#!/bin/bashsource ./math_advanced.shecho "Factorial of 5: $(factorial 5)"
echo "10th Fibonacci number: $(fibonacci 10)"

输出:

Factorial of 5: 120
10th Fibonacci number: 55

6.3 版本控制

对模块进行版本控制可以帮助管理依赖关系和跟踪变更。

示例11:模块版本控制

在每个模块文件的开头,添加版本信息:

# File: string_utils.sh
# Version: 1.2.0VERSION="1.2.0"# ... 函数定义 ...# 获取模块版本
get_version() {echo $VERSION
}

在主脚本中检查版本:

#!/bin/bashsource ./string_utils.shrequired_version="1.1.0"
current_version=$(get_version)if [[ "$(printf '%s\n' "$required_version" "$current_version" | sort -V | head -n1)" = "$required_version" ]]; thenecho "String utils module version $current_version is compatible"
elseecho "Error: String utils module version $current_version is not compatible. Required version: $required_version"exit 1
fi# ... 使用模块功能 ...

7. 常见问题和解决方案

在使用模块化Shell脚本时,可能会遇到一些常见问题。让我们探讨这些问题及其解决方案。

7.1 循环依赖

循环依赖发生在两个或多个模块相互依赖的情况下。

示例12:解决循环依赖

假设我们有两个相互依赖的模块:

# module_a.sh
source ./module_b.shfunction_a() {echo "Function A"function_b
}# module_b.sh
source ./module_a.shfunction_b() {echo "Function B"function_a
}

解决方案:重构代码以消除循环依赖,或使用主脚本来管理依赖:

# main.sh
source ./module_a.sh
source ./module_b.shfunction_a
function_b

7.2 命名冲突

当多个模块定义相同名称的函数或变量时,可能会发生命名冲突。

示例13:避免命名冲突

使用命名空间或前缀来避免冲突:

# math_module.sh
math_add() {echo $(($1 + $2))
}# string_module.sh
string_add() {echo "$1$2"
}# main.sh
source ./math_module.sh
source ./string_module.shecho "Math add: $(math_add 5 3)"
echo "String add: $(string_add "Hello" "World")"

7.3 性能考虑

过度使用模块可能会影响脚本的性能,特别是在处理大量小函数时。

示例14:优化模块加载

使用延迟加载技术:

#!/bin/bash# 延迟加载函数
load_module() {if [ -z "$MODULE_LOADED" ]; thensource ./heavy_module.shMODULE_LOADED=truefi
}# 包装函数
heavy_function() {load_module_heavy_function "$@"
}# 使用函数
heavy_function arg1 arg2

8. 实战项目:构建模块化的Shell应用

让我们通过一个实际的项目来综合应用我们所学的知识。我们将创建一个简单的日志分析工具,它由多个模块组成。

项目结构:

log_analyzer/
├── main.sh
├── modules/
│   ├── file_utils.sh
│   ├── log_parser.sh
│   └── report_generator.sh
└── config.sh

config.sh:

#!/bin/bash# Configuration file for log analyzer# Log file path
LOG_FILE="/var/log/app.log"# Report output directory
REPORT_DIR="./reports"# Log patterns
ERROR_PATTERN="ERROR"
WARNING_PATTERN="WARNING"# Report format (text or html)
REPORT_FORMAT="html"

modules/file_utils.sh:

#!/bin/bash# File utility functions# Check if a file exists and is readable
file_check_readable() {if [[ -r "$1" ]]; thenreturn 0elseecho "Error: File '$1' does not exist or is not readable." >&2return 1fi
}# Create directory if it doesn't exist
file_ensure_dir() {if [[ ! -d "$1" ]]; thenmkdir -p "$1"echo "Created directory: $1"fi
}

modules/log_parser.sh:

#!/bin/bash# Log parsing functions# Count occurrences of a pattern in a file
log_count_pattern() {local file="$1"local pattern="$2"grep -c "$pattern" "$file"
}# Extract lines matching a pattern
log_extract_lines() {local file="$1"local pattern="$2"grep "$pattern" "$file"
}

modules/report_generator.sh:

#!/bin/bash# Report generation functions# Generate HTML report
report_generate_html() {local output_file="$1"local error_count="$2"local warning_count="$3"local error_lines="$4"local warning_lines="$5"cat << EOF > "$output_file"
<html>
<head><title>Log Analysis Report</title></head>
<body>
<h1>Log Analysis Report</h1>
<p>Error Count: $error_count</p>
<p>Warning Count: $warning_count</p>
<h2>Error Lines:</h2>
<pre>$error_lines</pre>
<h2>Warning Lines:</h2>
<pre>$warning_lines</pre>
</body>
</html>
EOFecho "HTML report generated: $output_file"
}# Generate text report
report_generate_text() {local output_file="$1"local error_count="$2"local warning_count="$3"local error_lines="$4"local warning_lines="$5"cat << EOF > "$output_file"
Log Analysis Report
===================
Error Count: $error_count
Warning Count: $warning_countError Lines:
$error_linesWarning Lines:
$warning_lines
EOFecho "Text report generated: $output_file"
}

main.sh:

#!/bin/bash# Main script for log analyzer# Source configuration and modules
source ./config.sh
source ./modules/file_utils.sh
source ./modules/log_parser.sh
source ./modules/report_generator.sh# Check if log file exists and is readable
if ! file_check_readable "$LOG_FILE"; thenexit 1
fi# Ensure report directory exists
file_ensure_dir "$REPORT_DIR"# Parse log file
error_count=$(log_count_pattern "$LOG_FILE" "$ERROR_PATTERN")
warning_count=$(log_count_pattern "$LOG_FILE" "$WARNING_PATTERN")
error_lines=$(log_extract_lines "$LOG_FILE" "$ERROR_PATTERN")
warning_lines=$(log_extract_lines "$LOG_FILE" "$WARNING_PATTERN")# Generate report
timestamp=$(date +"%Y%m%d_%H%M%S")
report_file="$REPORT_DIR/report_$timestamp.$REPORT_FORMAT"
if [[ "$REPORT_FORMAT" == "html" ]]; thenreport_generate_html "$report_file" "$error_count" "$warning_count" "$error_lines" "$warning_lines"
elsereport_generate_text "$report_file" "$error_count" "$warning_count" "$error_lines" "$warning_lines"
fi
echo "Log analysis complete. Report generated at $report_file"

这个项目展示了如何使用模块化方法来构建一个更复杂的Shell应用。它包含了配置管理、文件操作、日志解析和报告生成等功能,每个功能都被封装在独立的模块中,使得代码更易于维护和扩展。

9. 总结

在本文中,我们深入探讨了Shell脚本中的模块引用技术。我们学习了基本的模块引用方法,如何创建和组织不同类型的模块,以及一些高级的模块引用技巧。我们还讨论了模块化编程的最佳实践,包括命名约定、文档和注释,以及版本控制。
通过实战项目,我们看到了如何将这些概念应用到实际的脚本开发中,创建一个模块化、可维护的Shell应用。
模块化不仅可以提高代码的可读性和可维护性,还能促进代码重用,提高开发效率。然而,在使用模块化方法时,我们也需要注意避免过度模块化导致的复杂性增加,并始终关注性能优化。
随着您在Shell脚本开发中积累更多经验,您将能够更好地平衡模块化带来的好处和潜在的挑战,创建出更加健壮和高效的脚本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/56953.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零开始学PHP之helloworld

前言 每一门编程语言的第一个程序就是输出hell world&#xff08;别杠&#xff0c;杠就是你对&#xff09; 开始 上一篇讲完了开发环境的安装&#xff0c;这次讲编辑器的安装&#xff0c;顺带完成上一篇的作业&#xff08;输出hello world&#xff09; 安装PHPstorm 我用的…

基于SpringBoot+Vue的旅游服务平台【提供源码+答辩PPT+参考文档+项目部署】

&#x1f4a5; ① 前言&#xff1a;这两年毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的JavaWeb项目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff01; ❗② 如何解决这类问题&#xff1f; 让我们能够顺利通过毕业&#xff0c;我也一直在不断思考、…

用自己的数据集复现YOLOv5

yolov5已经出了很多版本了&#xff0c;这里我以目前最新的版本为例&#xff0c;先在官网下载源码&#xff1a;GitHub - ultralytics/yolov5: YOLOv5 &#x1f680; in PyTorch > ONNX > CoreML > TFLite 然后下载预训练模型&#xff0c;需要哪个就点击哪个模型就行&am…

AI 编译器学习笔记之六 -- 基础知识、概念

1、激活函数&#xff1a; 深度学习—激活函数详解&#xff08;Sigmoid、tanh、ReLU、ReLU6及变体P-R-Leaky、ELU、SELU、Swish、Mish、Maxout、hard-sigmoid、hard-swish&#xff09;-CSDN博客 2、ModuleList和Sequential的区别&#xff1a;ModuleList是定义了一个迭代循环体…

机器视觉入门基础相关概念一 ——单目相机模型

机器视觉入门基础相关概念 相机模型 引言介绍&#xff1a;如果只是希望获取图像上的一些信息&#xff08;例如特征提取、拟合等&#xff09;&#xff0c;那么我们不会对三维空间中相机的位置有所要求。但如果希望通过二维的图像去理解三维空间中摄像机的信息&#xff0c;或者是…

【Qt】控件——Qt按钮类控件、常用的按钮类控件、按钮类控件的使用、Push Button、Radio Button、Check Box

文章目录 Qt3. Qt按钮类控件Push ButtonRadio ButtonCheck Box Qt 3. Qt按钮类控件 Push Button 使用 QPushButton 表示一个按钮。当点击按钮时可以触发各种事件。QPushButton 继承自 QAbstractButton。这个类是一个抽象类。是其他按钮的父类。 PushButton和QAbstractButton的…

阿里云linux系统扩容分区

系统扩容需要进行三步操作&#xff1a;①服务器扩容云盘 ② 扩容分区 ③ 扩容文件系统 参考&#xff1a;https://help.aliyun.com/zh/ecs/user-guide/extend-the-partitions-and-file-systems-of-disks-on-a-linux-instance?spma2c4g.11186623.0.0.6a094862DCMnnM#de3365e1d4l…

部署项目最新教程

​ 3.3安装mysql 运行代码&#xff1a; yum install mysql 运行代码&#xff1a; yum install mysql-server 中间还是一样要输入y然后回车 运行代码&#xff1a; yum install mysql-devel 好&#xff0c;经过上面三步&#xff0c;mysql安装成功&#xff0c;现在启动mysql…

国内如何下载谷歌浏览器(chrome浏览器)历史版本和chromedriver驱动,长期更新,建议收藏

众所周知&#xff0c;google是一直被国内屏蔽的&#xff0c;有时候想要下载个chrome浏览器都要去外网&#xff0c;或者到处去搜索才能下载到。因为下载chrome浏览器的这个网址&#xff1a;google.com/chrome/ 在国内是一直被屏蔽掉的。 今天主要讲解的是国内ChromeDriver 的下…

mac安装brew时踩坑解决方案

安装包 mac上如果按照git等工具可能会使用brew&#xff0c;例如使用&#xff1a;$ brew install git命令&#xff0c;如果电脑没有按照brew&#xff0c;则会提示&#xff1a;zsh: command not found: brew 解决方案 需要我们打开brew的官网https://brew.sh/&#xff0c;复制…

spring |Spring Security安全框架 —— 认证流程实现

文章目录 开头简介环境搭建入门使用1、认证1、实体类2、Controller层3、Service层3.1、接口3.2、实现类3.3、实现类&#xff1a;UserDetailsServiceImpl 4、Mapper层3、自定义token认证filter 注意事项小结 开头 Spring Security 官方网址&#xff1a;Spring Security官网 开…

Java @RequestPart注解:同时实现文件上传与JSON对象传参

RequestPart注解&#xff1a;用于处理multipart/form-data请求的一部分&#xff0c;通常用于文件上传或者处理表单中的字段。 java后端举例&#xff1a; PostMapping("/fileTest")public AjaxResult fileTest(RequestPart("file") MultipartFile file,Req…

2023年五一杯数学建模C题双碳目标下低碳建筑研究求解全过程论文及程序

2023年五一杯数学建模 C题 双碳目标下低碳建筑研究 原题再现&#xff1a; “双碳”即碳达峰与碳中和的简称&#xff0c;我国力争2030年前实现碳达峰&#xff0c;2060年前实现碳中和。“双碳”战略倡导绿色、环保、低碳的生活方式。我国加快降低碳排放步伐&#xff0c;大力推进…

模型评估与交叉验证:提升机器学习模型泛化性能的有效策略

模型评估与交叉验证&#xff1a;提升机器学习模型泛化性能的有效策略 目录 &#x1f3af; 模型评估的重要性&#x1f504; 交叉验证的基本概念&#x1f4ca; 交叉验证的实现⚙️ 常见的交叉验证策略&#x1f4c8; 模型选择与超参数调优&#x1f4a1; 结合模型评估与交叉验证的…

32. 问题 - EQ工具不能用

1. 概述 按照工具要求,修改代码中的宏,开启EQ调试功能

位运算题目-Java实现-LeetCode题解:判断字符是否唯一-丢失的数字-两整数之和-只出现一次的数字 II-消失的两个数字

这里是Themberfue 上一篇文章讲完了常见位运算的技巧以及总结 那么本章则通过五道题来运用这些技巧 判定字符是否唯一 题目解析 本题要求判断给定字符串中的字符是否唯一&#xff0c;也就是每个字符是否只出现一次 算法讲解 本题用哈希表遍历每一个字符也可以解决 如果这题使…

网络空间安全之一个WH的超前沿全栈技术深入学习之路(二:渗透测试行业术语扫盲)作者——LJS

欢迎各位彦祖与热巴畅游本人专栏与博客 你的三连是我最大的动力 以下图片仅代表专栏特色 [点击箭头指向的专栏名即可闪现] 专栏跑道一 ➡️网络空间安全——全栈前沿技术持续深入学习 专栏跑道二 ➡️ 24 Network Security -LJS ​ ​ ​ 专栏跑道三 ➡️ MYSQL REDIS Advan…

Java Memory Model

内存模型 JMM(Java 内存模型)主要定义了对于一个共享变量&#xff0c;当另一个线程对这个共享变量执行写操作后&#xff0c;这个线程对这个共享变量的可见性。 Java Memory Model&#xff08;JMM&#xff09;&#xff0c;本身是一种抽象的概念&#xff0c;实际上并不存在&…

头戴耳机最值得购买的牌子有哪些?四款公认口碑和性价比高推荐

说到头戴式耳机&#xff0c;大部分人都会面另一个问题&#xff0c;那就是如何选购一款好用实惠的头戴耳机。有的人图便宜&#xff0c;结果不仅音质不好&#xff0c;佩戴还不舒服&#xff0c;而有的人图牌子&#xff0c;结果却交了“智商税”&#xff01;俗话说买对不买贵&#…

ubuntu2404下搭建Odoo18开发环境

Odoo在windows下也可以开发&#xff0c;不过执行速度比较慢&#xff0c;经过我测试&#xff0c;重启一下服务&#xff0c;windows下需要十几秒甚至几十秒&#xff0c;而mac或者ubuntu只需要几秒钟。 另外&#xff0c;官方推荐的生产环境也是ubuntu&#xff0c;所以&#xff0c…