linux bash shell:最方便的字符串大小写转换(lowercase/uppercase conversion)

本文介绍Bash4.0以上版本中使用${parameter,,pattern}

关于字符串大小写转换,是写 linux 脚本经常干的事儿,所以总想找个方便的方法让我少打点字儿,搜索国内的中文资源,网上也能找到很多关于这个帖子,介绍的方法都差不多,用typeset是最简单的方法了,但我觉得还是不够简单,因为需要多定义一个变量。

google上找到这个stackoverflow上的帖子,才知道Bash 4.0以上版本有更好的办法:

《How to convert a string to lower case in Bash?》

就是${parameter,,pattern},${parameter^^pattern}表达式,表达不会改变原来变量的值

#! /bin/bash
# 注意:脚本第一行一定要注明脚本解释器是bash.不能是sh,或dash
# 因为sh软连接有可能指向的是dash
var="Hello,Word"
# 把变量中的第一个字符换成大写 
echo ${var^} 
# 把变量中的所有小写字母,全部替换为大写
echo ${var^^}   
# 把变量中的第一个字符换成小写
echo ${var,}
# 把变量中的所有大写字母,全部替换为小写
echo ${var,,}

Bash 4.0是2009年发布的版本,现在的应用已经很广泛了,我现在用的ubuntu 16默认安装的就是bash 4.3,centos 6.5下默认安装的是4.1.所以只要不是太老的linux版本,都不会有兼容性问题。

关于${parameter,,pattern},${parameter^^pattern}表达式更全面的说明参见下面Bash的官方手册:

《Bash Reference Manual》

#下面是一个MCP服务器程序,请考察一下 #!/usr/bin/env python3 """ 使用FastMCP的小MCP服务器示例 - 带图形界面和多个工具 """ import sys import asyncio import json import random import math import threading import socket from datetime import datetime from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit, QPushButton, QLabel, QLineEdit, QGroupBox, QListWidget, QSplitter, QStatusBar, QMessageBox, QComboBox, QSpinBox, QDoubleSpinBox, QCheckBox, QTabWidget, QScrollArea) from PyQt5.QtCore import Qt, QThread, pyqtSignal from PyQt5.QtGui import QFont, QTextCursor, QPixmap, QColor import base64 from io import BytesIO # 导入FastMCP相关功能 from fastmcp import FastMCP import numpy as np import matplotlib.pyplot as plt # 创建FastMCP服务器实例 mcp = FastMCP("enhanced-mcp-server") # 存储工具信息 TOOLS = [ { "name": "calculate", "description": "执行数学计算", "parameters": [ { "name": "expression", "type": "string", "description": "数学表达式,例如: 2 + 3 * 4" } ] }, { "name": "generate_plot", "description": "生成简单的函数图像", "parameters": [ { "name": "function", "type": "string", "description": "函数表达式,例如: np.sin(x)" }, { "name": "x_min", "type": "float", "description": "X轴小值", "default": -10.0 }, { "name": "x_max", "type": "float", "description": "X轴大值", "default": 10.0 } ] }, { "name": "random_number", "description": "生成指定范围内的随机数", "parameters": [ { "name": "min_value", "type": "int", "description": "小值", "default": 1 }, { "name": "max_value", "type": "int", "description": "大值", "default": 100 }, { "name": "count", "type": "int", "description": "生成数量", "default": 1 } ] }, { "name": "string_operations", "description": "字符串操作工具", "parameters": [ { "name": "operation", "type": "choice", "description": "选择操作类型", "choices": ["reverse", "uppercase", "lowercase", "length"], "default": "reverse" }, { "name": "input_string", "type": "string", "description": "输入字符串" } ] }, { "name": "unit_converter", "description": "单位转换工具", "parameters": [ { "name": "conversion_type", "type": "choice", "description": "选择转换类型", "choices": ["celsius_to_fahrenheit", "fahrenheit_to_celsius", "meters_to_feet", "feet_to_meters", "kg_to_lb", "lb_to_kg"], "default": "celsius_to_fahrenheit" }, { "name": "value", "type": "float", "description": "输入要转换的值", "default": 0.0 } ] }, { "name": "date_calculator", "description": "日期计算工具", "parameters": [ { "name": "operation", "type": "choice", "description": "选择操作类型", "choices": ["current_date", "add_days", "difference"], "default": "current_date" }, { "name": "date", "type": "string", "description": "日期 (YYYY-MM-DD)", "default": datetime.now().strftime("%Y-%m-%d") }, { "name": "days", "type": "int", "description": "天数", "default": 0 }, { "name": "date2", "type": "string", "description": "第二个日期 (YYYY-MM-DD)", "default": datetime.now().strftime("%Y-%m-%d") } ] }, { "name": "statistical_calculator", "description": "统计计算工具", "parameters": [ { "name": "operation", "type": "choice", "description": "选择操作类型", "choices": ["mean", "median", "std", "min", "max"], "default": "mean" }, { "name": "numbers", "type": "string", "description": "数字列表,用逗号分隔", "default": "1,2,3,4,5" } ] } ] # 定义工具函数的实现(不添加装饰器) def calculate_impl(expression: str) -> str: """执行数学计算""" try: result = eval(expression, {"__builtins__": {}}) return f"计算结果: {result}" except Exception as e: return f"计算错误: {e}" def generate_plot_impl(function: str, x_min: float = -10, x_max: float = 10) -> dict: """生成简单的函数图像""" try: # 生成函数图像 x = np.linspace(x_min, x_max, 100) y = eval(function, {'x': x, 'np': np}) # 创建图像 plt.figure(figsize=(8, 6)) plt.plot(x, y) plt.title(f"函数图像: {function}") plt.xlabel('x') plt.ylabel('y') plt.grid(True) # 将图像转换为base64 buf = BytesIO() plt.savefig(buf, format='png') buf.seek(0) img_base64 = base64.b64encode(buf.read()).decode('utf-8') plt.close() return { "type": "image", "data": img_base64, "mimeType": "image/png" } except Exception as e: return {"type": "text", "content": f"生成图像错误: {e}"} def random_number_impl(min_value: int = 1, max_value: int = 100, count: int = 1) -> str: """生成指定范围内的随机数""" try: if count == 1: result = random.randint(min_value, max_value) return f"随机数: {result}" else: results = [random.randint(min_value, max_value) for _ in range(count)] return f"随机数列表: {results}" except Exception as e: return f"生成随机数错误: {e}" def string_operations_impl(operation: str, input_string: str) -> str: """字符串操作工具""" try: if operation == "reverse": result = input_string[::-1] return f"反转后的字符串: {result}" elif operation == "uppercase": result = input_string.upper() return f"大写字符串: {result}" elif operation == "lowercase": result = input_string.lower() return f"小写字符串: {result}" elif operation == "length": result = len(input_string) return f"字符串长度: {result}" else: return f"未知操作: {operation}" except Exception as e: return f"字符串操作错误: {e}" def unit_converter_impl(conversion_type: str, value: float) -> str: """单位转换工具""" try: if conversion_type == "celsius_to_fahrenheit": result = (value * 9 / 5) + 32 return f"{value}°C = {result:.2f}°F" elif conversion_type == "fahrenheit_to_celsius": result = (value - 32) * 5 / 9 return f"{value}°F = {result:.2f}°C" elif conversion_type == "meters_to_feet": result = value * 3.28084 return f"{value}米 = {result:.2f}英尺" elif conversion_type == "feet_to_meters": result = value / 3.28084 return f"{value}英尺 = {result:.2f}米" elif conversion_type == "kg_to_lb": result = value * 2.20462 return f"{value}千克 = {result:.2f}磅" elif conversion_type == "lb_to_kg": result = value / 2.20462 return f"{value}磅 = {result:.2f}千克" else: return f"未知转换类型: {conversion_type}" except Exception as e: return f"单位转换错误: {e}" def date_calculator_impl(operation: str, date: str, days: int = 0, date2: str = "") -> str: """日期计算工具""" try: from datetime import datetime, timedelta if operation == "current_date": current_date = datetime.now().strftime("%Y-%m-%d") return f"当前日期: {current_date}" elif operation == "add_days": date_obj = datetime.strptime(date, "%Y-%m-%d") new_date = date_obj + timedelta(days=days) return f"{date} 加 {days} 天后的日期: {new_date.strftime('%Y-%m-%d')}" elif operation == "difference": date1_obj = datetime.strptime(date, "%Y-%m-%d") date2_obj = datetime.strptime(date2, "%Y-%m-%d") delta = abs((date2_obj - date1_obj).days) return f"{date} 和 {date2} 相差 {delta} 天" else: return f"未知操作: {operation}" except Exception as e: return f"日期计算错误: {e}" def statistical_calculator_impl(operation: str, numbers: str) -> str: """统计计算工具""" try: # 将字符串转换为数字列表 num_list = [float(x.strip()) for x in numbers.split(",")] if operation == "mean": result = sum(num_list) / len(num_list) return f"平均值: {result:.2f}" elif operation == "median": sorted_nums = sorted(num_list) n = len(sorted_nums) if n % 2 == 0: result = (sorted_nums[n // 2 - 1] + sorted_nums[n // 2]) / 2 else: result = sorted_nums[n // 2] return f"中位数: {result:.2f}" elif operation == "std": mean = sum(num_list) / len(num_list) variance = sum((x - mean) ** 2 for x in num_list) / len(num_list) result = math.sqrt(variance) return f"标准差: {result:.2f}" elif operation == "min": result = min(num_list) return f"小值: {result:.2f}" elif operation == "max": result = max(num_list) return f"大值: {result:.2f}" else: return f"未知操作: {operation}" except Exception as e: return f"统计计算错误: {e}" # 使用装饰器注册工具(这些将用于MCP客户端调用) @mcp.tool() def calculate(expression: str) -> str: return calculate_impl(expression) @mcp.tool() def generate_plot(function: str, x_min: float = -10, x_max: float = 10) -> dict: return generate_plot_impl(function, x_min, x_max) @mcp.tool() def random_number(min_value: int = 1, max_value: int = 100, count: int = 1) -> str: return random_number_impl(min_value, max_value, count) @mcp.tool() def string_operations(operation: str, input_string: str) -> str: return string_operations_impl(operation, input_string) @mcp.tool() def unit_converter(conversion_type: str, value: float) -> str: return unit_converter_impl(conversion_type, value) @mcp.tool() def date_calculator(operation: str, date: str, days: int = 0, date2: str = "") -> str: return date_calculator_impl(operation, date, days, date2) @mcp.tool() def statistical_calculator(operation: str, numbers: str) -> str: return statistical_calculator_impl(operation, numbers) # 添加自定义工具列表方法 @mcp.tool() def tools_list(): """返回工具列表""" # 将TOOLS转换为MCP协议要求的格式 mcp_tools = [] for tool in TOOLS: mcp_tool = { "name": tool["name"], "description": tool["description"], "inputSchema": { "type": "object", "properties": {}, "required": [] } } # 添加参数信息 for param in tool["parameters"]: param_name = param["name"] param_type = param["type"] # 将参数类型映射到JSON Schema类型 type_mapping = { "string": "string", "int": "integer", "float": "number", "choice": "string" } mcp_tool["inputSchema"]["properties"][param_name] = { "type": type_mapping.get(param_type, "string"), "description": param.get("description", "") } # 如果是选择类型,添加枚举值 if param_type == "choice" and "choices" in param: mcp_tool["inputSchema"]["properties"][param_name]["enum"] = param["choices"] # 如果有默认值,添加到参数中 if "default" in param: mcp_tool["inputSchema"]["properties"][param_name]["default"] = param["default"] # 添加到必需参数列表 mcp_tool["inputSchema"]["required"].append(param_name) mcp_tools.append(mcp_tool) return {"tools": mcp_tools} # 资源相关功能 @mcp.resource("resource://enhanced-mcp-server/help") def get_help() -> str: """获取帮助文档""" help_text = """ # 增强MCP服务器帮助文档 ## 可用工具 """ for tool in TOOLS: help_text += f"\n### {tool['name']}\n" help_text += f"- 描述: {tool['description']}\n" help_text += "- 参数:\n" for param in tool['parameters']: param_desc = f" - {param['name']} ({param['type']})" if 'default' in param: param_desc += f" [默认: {param['default']}]" if 'description' in param: param_desc += f": {param['description']}" help_text += param_desc + "\n" return help_text class MCPServerGUI(QMainWindow): """MCP服务器图形界面""" def __init__(self): super().__init__() # 获取本机IP地址 self.host_ip = self.get_host_ip() # 设置服务器端口 self.server_port = 8000 self.setup_ui() self.setWindowTitle("MCP服务器 - 增强工具界面") self.resize(1000, 700) # 存储生成的图像 self.current_image = None # 启动MCP服务器线程 self.start_mcp_server() def get_host_ip(self): """获取本机IP地址""" try: # 创建一个临时socket连接来获取本机IP s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) ip = s.getsockname()[0] s.close() return ip except: return "127.0.0.1" def start_mcp_server(self): """启动MCP服务器线程""" self.server_thread = threading.Thread(target=self.run_mcp_server) self.server_thread.daemon = True self.server_thread.start() self.statusBar().showMessage(f"MCP服务器已启动 - 监听地址: {self.host_ip}:{self.server_port}") def run_mcp_server(self): """运行MCP服务器""" try: # 使用HTTP传输模式 mcp.run(transport="http", host="0.0.0.0", port=self.server_port) except Exception as e: print(f"服务器启动错误: {e}") # 在GUI中显示错误信息 self.statusBar().showMessage(f"服务器启动失败: {str(e)}") def setup_ui(self): """设置用户界面""" # 中央部件 central_widget = QWidget() self.setCentralWidget(central_widget) # 主布局 main_layout = QHBoxLayout(central_widget) # 创建分割器 splitter = QSplitter(Qt.Horizontal) # 左侧面板 - 工具选择 left_panel = QWidget() left_layout = QVBoxLayout(left_panel) # 服务器信息组 server_group = QGroupBox("服务器状态") server_layout = QVBoxLayout(server_group) # 显示服务器连接信息 server_info = QLabel(f""" <b>MCP服务器正在运行中...</b> <br><br> <b>监听地址:</b> 0.0.0.0 (所有接口) <br> <b>监听端口:</b> {self.server_port} <br><br> <b>客户端连接地址:</b> <br> - 本地连接: 127.0.0.1:{self.server_port} <br> - 网络连接: {self.host_ip}:{self.server_port} <br><br> 客户端可以使用上述任一地址连接到本服务器, 获取工具列表并调用工具功能。 """) server_info.setWordWrap(True) server_info.setTextFormat(Qt.RichText) server_layout.addWidget(server_info) # 工具选择组 tool_group = QGroupBox("选择工具") tool_layout = QVBoxLayout(tool_group) self.tool_combo = QComboBox() for tool in TOOLS: self.tool_combo.addItem(f"{tool['name']} - {tool['description']}") self.tool_combo.currentTextChanged.connect(self.on_tool_changed) tool_layout.addWidget(QLabel("选择工具:")) tool_layout.addWidget(self.tool_combo) # 参数输入组 self.params_group = QGroupBox("工具参数") self.params_layout = QVBoxLayout(self.params_group) self.params_layout.setAlignment(Qt.AlignTop) # 为每个工具创建参数输入控件 self.tool_widgets = {} for tool in TOOLS: widget = self.create_tool_widget(tool) self.tool_widgets[tool['name']] = widget if tool['name'] != "calculate": # 默认显示第一个工具 widget.hide() # 执行按钮 self.execute_btn = QPushButton("执行工具") self.execute_btn.clicked.connect(self.execute_tool) # 添加到左侧布局 left_layout.addWidget(server_group) left_layout.addWidget(tool_group) left_layout.addWidget(self.params_group) left_layout.addWidget(self.execute_btn) left_layout.setStretch(2, 2) # 参数组占用更多空间 # 右侧面板 - 输出 right_panel = QWidget() right_layout = QVBoxLayout(right_panel) # 创建选项卡 self.tab_widget = QTabWidget() # 文本输出选项卡 output_group = QWidget() output_layout = QVBoxLayout(output_group) self.output_area = QTextEdit() self.output_area.setReadOnly(True) self.output_area.setFont(QFont("Courier", 10)) output_layout.addWidget(self.output_area) # 图像显示选项卡 image_group = QWidget() image_layout = QVBoxLayout(image_group) self.image_label = QLabel() self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setText("图像将在这里显示") self.image_label.setMinimumHeight(400) # 创建滚动区域用于图像 scroll_area = QScrollArea() scroll_area.setWidget(self.image_label) scroll_area.setWidgetResizable(True) image_layout.addWidget(scroll_area) # 添加选项卡 self.tab_widget.addTab(output_group, "文本输出") self.tab_widget.addTab(image_group, "图像输出") # 添加到右侧布局 right_layout.addWidget(self.tab_widget) # 添加到分割器 splitter.addWidget(left_panel) splitter.addWidget(right_panel) splitter.setSizes([400, 600]) # 设置初始大小比例 # 添加到主布局 main_layout.addWidget(splitter) # 状态栏 self.statusBar().showMessage(f"服务器已启动 - 监听地址: {self.host_ip}:{self.server_port}") # 设置样式 self.apply_styles() def create_tool_widget(self, tool): """为工具创建参数输入控件""" widget = QWidget() layout = QVBoxLayout(widget) layout.setAlignment(Qt.AlignTop) self.input_fields = {} for param in tool['parameters']: param_name = param["name"] param_type = param.get("type", "string") param_desc = param.get("description", "") param_default = param.get("default", "") # 创建标签 label = QLabel(f"{param_name}:") label.setToolTip(param_desc) # 根据参数类型创建输入控件 if param_type == "choice": input_widget = QComboBox() for choice in param.get("choices", []): input_widget.addItem(choice) if param_default and param_default in param.get("choices", []): input_widget.setCurrentText(param_default) elif param_type == "int": input_widget = QSpinBox() input_widget.setRange(-100000, 100000) input_widget.setValue(int(param_default) if param_default else 0) elif param_type == "float": input_widget = QDoubleSpinBox() input_widget.setRange(-100000, 100000) input_widget.setDecimals(4) input_widget.setValue(float(param_default) if param_default else 0.0) else: # 默认为字符串输入 input_widget = QLineEdit() input_widget.setPlaceholderText(param_desc) if param_default: input_widget.setText(str(param_default)) self.input_fields[param_name] = input_widget # 添加到布局 layout.addWidget(label) layout.addWidget(input_widget) return widget def apply_styles(self): """应用样式""" self.setStyleSheet(""" QMainWindow { background-color: #f0f0f0; } QGroupBox { font-weight: bold; border: 2px solid #cccccc; border-radius: 5px; margin-top: 1ex; padding-top: 10px; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 5px 0 5px; } QPushButton { background-color: #4a86e8; color: white; border: none; padding: 8px; border-radius: 4px; font-weight: bold; } QPushButton:hover { background-color: #3a76d8; } QPushButton:disabled { background-color: #cccccc; color: #888888; } QTextEdit { background-color: #fafafa; border: 1px solid #cccccc; border-radius: 4px; } QComboBox, QLineEdit, QDoubleSpinBox, QSpinBox { padding: 6px; border: 1px solid #cccccc; border-radius: 4px; background-color: white; } QLabel { font-weight: bold; } QTabWidget::pane { border: 1px solid #cccccc; background-color: #fafafa; } QTabBar::tab { background-color: #e0e0e0; padding: 8px; margin-right: 2px; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:selected { background-color: #fafafa; border-bottom: 2px solid #4a86e8; } """) def on_tool_changed(self, tool_text): """当选择的工具改时""" # 获取工具名称 tool_name = tool_text.split(" - ")[0] # 隐藏所有工具参数控件 for widget in self.tool_widgets.values(): widget.hide() # 显示当前工具的参数控件 if tool_name in self.tool_widgets: self.tool_widgets[tool_name].show() # 清除之前的输出 self.output_area.clear() self.hide_image() def execute_tool(self): """执行选定的工具""" tool_text = self.tool_combo.currentText() tool_name = tool_text.split(" - ")[0] try: # 获取参数值 params = {} if tool_name in self.tool_widgets: for param_name, input_widget in self.input_fields.items(): if isinstance(input_widget, QComboBox): params[param_name] = input_widget.currentText() elif isinstance(input_widget, (QSpinBox, QDoubleSpinBox)): params[param_name] = input_widget.value() else: # QLineEdit params[param_name] = input_widget.text() # 调用相应的工具实现函数 if tool_name == "calculate": result = calculate_impl(params.get("expression", "")) self.output_area.append(f"计算表达式: {params.get('expression', '')}") self.output_area.append(f"结果: {result}") self.hide_image() elif tool_name == "generate_plot": result = generate_plot_impl( params.get("function", ""), params.get("x_min", -10), params.get("x_max", 10) ) self.output_area.append(f"生成函数图像: {params.get('function', '')}") self.output_area.append(f"X轴范围: [{params.get('x_min', -10)}, {params.get('x_max', 10)}]") if result["type"] == "image": # 显示图像 img_data = base64.b64decode(result["data"]) pixmap = QPixmap() pixmap.loadFromData(img_data) # 缩放图像以适应标签 scaled_pixmap = pixmap.scaled( self.image_label.width(), self.image_label.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.image_label.setPixmap(scaled_pixmap) self.tab_widget.setCurrentIndex(1) # 切换到图像选项卡 self.output_area.append("图像生成成功!") else: self.output_area.append(f"错误: {result['content']}") self.hide_image() elif tool_name == "random_number": result = random_number_impl( params.get("min_value", 1), params.get("max_value", 100), params.get("count", 1) ) self.output_area.append(result) self.hide_image() elif tool_name == "string_operations": result = string_operations_impl( params.get("operation", "reverse"), params.get("input_string", "") ) self.output_area.append(result) self.hide_image() elif tool_name == "unit_converter": result = unit_converter_impl( params.get("conversion_type", "celsius_to_fahrenheit"), params.get("value", 0.0) ) self.output_area.append(result) self.hide_image() elif tool_name == "date_calculator": result = date_calculator_impl( params.get("operation", "current_date"), params.get("date", datetime.now().strftime("%Y-%m-%d")), params.get("days", 0), params.get("date2", datetime.now().strftime("%Y-%m-%d")) ) self.output_area.append(result) self.hide_image() elif tool_name == "statistical_calculator": result = statistical_calculator_impl( params.get("operation", "mean"), params.get("numbers", "1,2,3,4,5") ) self.output_area.append(result) self.hide_image() self.statusBar().showMessage(f"{tool_name} 执行成功") self.tab_widget.setCurrentIndex(0) # 切换到文本输出选项卡 except Exception as e: error_msg = f"执行工具时出错: {str(e)}" self.output_area.append(error_msg) self.statusBar().showMessage(error_msg) QMessageBox.critical(self, "错误", error_msg) def hide_image(self): """隐藏图像""" self.image_label.clear() self.image_label.setText("图像将在这里显示") def resizeEvent(self, event): """窗口大小改时调整图像大小""" super().resizeEvent(event) # 修复:检查image_label是否有pixmap,以及pixmap是否有效 if hasattr(self, 'image_label') and self.image_label and self.image_label.pixmap() and not self.image_label.pixmap().isNull(): scaled_pixmap = self.image_label.pixmap().scaled( self.image_label.width(), self.image_label.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.image_label.setPixmap(scaled_pixmap) def run_server_gui(): """运行服务器图形界面""" app = QApplication(sys.argv) window = MCPServerGUI() window.show() sys.exit(app.exec_()) if __name__ == "__main__": # 直接运行GUI界面,同时启动MCP服务器 run_server_gui()
最新发布
09-16
/* * file char_dev.c * brief 注册字符设备. * * author Gaoziyue * version 1.0.0 * date 7Aug25 * * history \arg 1.0.0, 7Aug25, Gaoziyue, Create the file. */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h> #include <linux/device.h> #include <linux/slab.h> /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ /*设备名称*/ #define DEVICE_NAME "char_dev" /*设备类*/ #define CLASS_NAME "char_class" /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* EXTERN_PROTOTYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* LOCAL_PROTOTYPES */ /**************************************************************************************************/ static int char_open(struct inode* inode, struct file* file); static int char_release(struct inode* inode, struct file* file); static ssize_t char_write(struct file* file, const char __user* buf, size_t count, loff_t* offset); static int __init char_init(void); static void __exit char_exit(void); /**************************************************************************************************/ /* VARIABLES */ /**************************************************************************************************/ static int major_num = 0;/*主设备号*/ static struct class* char_class = NULL; static struct device* char_device = NULL; static struct cdev char_cdev;/*字符设备结构*/ static int cap = 0;/*模块参数,默认0,不转换大写*/ /**************************************************************************************************/ /* FUNCTIONS */ /**************************************************************************************************/ module_param(cap, int, S_IRUGO);/*定义模块参数cap,类型int,权限为只读*/ MODULE_PARM_DESC(cap, "Enable uppercase conversion (1=enable)");/*参数描述*/ /* * @brief 字符设备打开函数. * @param[in] inode 指向设备文件的inode结构(索引节点),包含设备号、文件属性等元数据. * @param[in] file 指向文件结构体,表示此次打开操作的上下文. * @return 返回0表示成功,返回负值表示错误. */ static int char_open(struct inode* inode, struct file* file) { printk(KERN_INFO "Char device opened\n"); return 0; } /* * @brief 字符设备关闭函数. * @param[in] inode 指向设备文件的inode结构(索引节点),包含设备号、文件属性等元数据. * @param[in] file 指向文件结构体,表示此次打开操作的上下文. * @return 返回0表示成功,返回负值表示错误. */ static int char_release(struct inode* inode, struct file* file) { printk(KERN_INFO "Char device closed\n"); return 0; } /* * @brief 写设备函数. * @param[in] file 当前打开的文件结构体. * @param[in] buf 待写入的原始数据指针. * @param[in] count 请求写入的字节数. * @param[in/out] offset 指向文件当前位置偏移量的指针. * @return 成功时返回写入字节数;失败时返回负错误码. */ static ssize_t char_write(struct file* file, const char __user* buf, size_t count, loff_t* offset) { char* kernel_buf = kmalloc(count + 1, GFP_KERNEL);/*分配内核缓冲区(+1为结尾的'\0')*/ if (NULL == kernel_buf) { printk(KERN_ALERT "Memory allocation failed\n"); return -ENOMEM; } /*从用户空间复制数据*/ if (copy_from_user(kernel_buf, buf, count)) { kfree(kernel_buf); return -EFAULT; } kernel_buf[count] = '\0'; /*确保字符串结尾*/ /*大小写转换*/ if (cap) { int i = 0; for (i = 0; i < count; i++) { if (kernel_buf[i] >= 'a' && kernel_buf[i] <= 'z') { kernel_buf[i] -= 32; /*转换为大写*/ } } } /*打印处理后的内容*/ printk(KERN_INFO "Received: %s\n", kernel_buf); kfree(kernel_buf); return count; } /* * brief 文件操作结构. */ static struct file_operations fops = { .owner = THIS_MODULE, /*指向当前模块*/ .open = char_open, /*打开函数*/ .release = char_release,/*关闭函数*/ .write = char_write, /*写函数*/ }; /* * brief 模块初始化. */ static int __init char_init(void) { /*分配设备号*/ if (alloc_chrdev_region(&major_num, 0, 1, DEVICE_NAME) < 0) { printk(KERN_ALERT "Failed to allocate device number\n"); return -1; } /*创建设备类*/ char_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(char_class)) { unregister_chrdev_region(major_num, 1); /*撤销设备号*/ printk(KERN_ALERT "Failed to create device class\n"); return PTR_ERR(char_class); } /*创建设备*/ char_device = device_create(char_class, NULL, major_num, NULL, DEVICE_NAME); if (IS_ERR(char_device)) { class_destroy(char_class); /*销毁类*/ unregister_chrdev_region(major_num, 1); /*撤销设备号*/ printk(KERN_ALERT "Failed to create device\n"); return PTR_ERR(char_device); } /*初始化字符设备*/ cdev_init(&char_cdev, &fops); if (cdev_add(&char_cdev, major_num, 1) < 0) { device_destroy(char_class, major_num); /*销毁设备*/ class_destroy(char_class); /*销毁类*/ unregister_chrdev_region(major_num, 1); /*撤销设备号*/ printk(KERN_ALERT "Failed to add cdev\n"); return -1; } printk(KERN_INFO "Char device loaded with cap=%d\n", cap); return 0; } /* * brief 模块退出. */ static void __exit char_exit(void) { cdev_del(&char_cdev); /*删除字符设备*/ device_destroy(char_class, major_num); /*销毁设备*/ class_destroy(char_class); /*销毁类*/ unregister_chrdev_region(major_num, 1); /*撤销设备号*/ printk(KERN_INFO "Char device unloaded\n"); } module_init(char_init); /*指定初始化函数*/ module_exit(char_exit); /*指定退出函数*/ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ma Qianyi"); MODULE_DESCRIPTION("Character device with case conversion"); 这个是我的代码,我想知道我现在怎么做才能对字符设备进行写操作,内核会将写入该字符设备的内容打印出来 可以正常安装卸载内核模块 内核模块可以带参数,cap=1时输入全转为大写输出
08-09
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值