ESP32 实现获取天气情况

按照小安派AiPi-Eyes天气站思路,在ESP32 S3上实现获取天气情况。

一、在ESP32 S3实现

1、main.c

建立2个TASK

void app_main(void)
{//lvgl初始化xTaskCreate(guiTask, "guiTask", 1024 * 6, NULL, 5, NULL);//wifi初始化、socket、json处理taskcustom_init();
}

2、guiTask()

lVGL初始化


void guiTask(void *pvParameter)
{xGuiSemaphore = xSemaphoreCreateMutex();static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)static lv_disp_drv_t disp_drv;      // contains callback functionsESP_LOGI(TAG, "Turn off LCD backlight");gpio_set_direction(PIN_NUM_RD, GPIO_MODE_OUTPUT);gpio_set_level(PIN_NUM_RD, 1);backlight_ledc_init();ESP_LOGI(TAG, "Initialize Intel 8080 bus");esp_lcd_i80_bus_handle_t i80_bus = NULL;esp_lcd_i80_bus_config_t bus_config = {.clk_src = LCD_CLK_SRC_DEFAULT,.dc_gpio_num = PIN_NUM_DC,.wr_gpio_num = PIN_NUM_PCLK,.data_gpio_nums = {PIN_NUM_DATA0,PIN_NUM_DATA1,PIN_NUM_DATA2,PIN_NUM_DATA3,PIN_NUM_DATA4,PIN_NUM_DATA5,PIN_NUM_DATA6,PIN_NUM_DATA7,},.bus_width = 8,.max_transfer_bytes = LCD_V_RES * 220 * sizeof(uint16_t),.psram_trans_align = PSRAM_DATA_ALIGNMENT,.sram_trans_align = 4,};ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));esp_lcd_panel_io_handle_t io_handle = NULL;esp_lcd_panel_io_i80_config_t io_config = {.cs_gpio_num = PIN_NUM_CS,.pclk_hz = LCD_PIXEL_CLOCK_HZ,.trans_queue_depth = 10,.dc_levels = {.dc_idle_level = 0,.dc_cmd_level = 0,.dc_dummy_level = 0,.dc_data_level = 1,},.on_color_trans_done = notify_lvgl_flush_ready,.user_ctx = &disp_drv,.lcd_cmd_bits = LCD_CMD_BITS,.lcd_param_bits = LCD_PARAM_BITS,.flags.swap_color_bytes = true,};ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));esp_lcd_panel_handle_t panel_handle = NULL;ESP_LOGI(TAG, "Install LCD driver of ili9225");esp_lcd_panel_dev_config_t panel_config = {.reset_gpio_num = PIN_NUM_RST,.color_space = ESP_LCD_COLOR_SPACE_RGB,.bits_per_pixel = 16,};ESP_ERROR_CHECK(esp_lcd_new_panel_ili9225(io_handle, &panel_config, &panel_handle));esp_lcd_panel_reset(panel_handle);esp_lcd_panel_init(panel_handle);ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));ESP_LOGI(TAG, "Initialize LVGL library");lv_init();// alloc draw buffers used by LVGL// it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sizedlv_color_t *buf1 = NULL;lv_color_t *buf2 = NULL;buf1 = heap_caps_malloc(LCD_V_RES * 50 * sizeof(lv_color_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);buf2 = heap_caps_malloc(LCD_V_RES * 50 * sizeof(lv_color_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);assert(buf1);assert(buf2);ESP_LOGI(TAG, "buf1@%p, buf2@%p", buf1, buf2);// initialize LVGL draw bufferslv_disp_draw_buf_init(&disp_buf, buf1, buf2, LCD_V_RES * 50);ESP_LOGI(TAG, "Register display driver to LVGL");lv_disp_drv_init(&disp_drv);disp_drv.hor_res = LCD_H_RES;disp_drv.ver_res = LCD_V_RES;disp_drv.flush_cb = lvgl_flush_cb;disp_drv.draw_buf = &disp_buf;disp_drv.user_data = panel_handle;// lv_disp_t *disp = lv_disp_drv_register(&disp_drv);lv_disp_drv_register(&disp_drv);ESP_LOGI(TAG, "Install LVGL tick timer");// Tick interface for LVGL (using esp_timer to generate 2ms periodic event)const esp_timer_create_args_t lvgl_tick_timer_args = {.callback = &increase_lvgl_tick,.name = "lvgl_tick"};esp_timer_handle_t lvgl_tick_timer = NULL;ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, LVGL_TICK_PERIOD_MS * 1000));ESP_ERROR_CHECK(ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8191));// Update duty to apply the new valueESP_ERROR_CHECK(ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));// First to print one framelv_timer_handler();lv_obj_t *screen = lv_obj_create(NULL);lv_obj_set_style_bg_color(screen,lv_color_hex(0x000000),LV_PART_MAIN);lv_scr_load(screen);static lv_style_t style;lv_style_init(&style);lv_style_set_bg_color(&style, lv_color_make(0xFF, 0xff, 0xff));lv_style_set_bg_opa(&style,LV_OPA_10);lv_style_set_border_color(&style, lv_color_make(0xFF, 0x00, 0xff));lv_style_set_text_color(&style,lv_color_make(0x00, 0x00, 0xff));label1=lv_label_create(lv_scr_act());lv_obj_add_style(label1, &style, 0);lv_obj_set_pos(label1, 10, 10);                                    /*Set its position*/lv_obj_set_size(label1, 160, 32);                                  /*Set its size*/lv_label_set_text(label1, "Weather");lv_obj_set_style_text_color(label1, lv_color_make(0xff, 0x00, 0x00), LV_PART_MAIN|LV_STATE_DEFAULT);//城市label_city=lv_label_create(lv_scr_act());lv_obj_set_pos(label_city, 10, 50);                                    /*Set its position*/lv_obj_set_size(label_city, 100, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_city, lv_color_make(0xff, 0xff, 0xff), LV_PART_MAIN|LV_STATE_DEFAULT);//温度label_tem=lv_label_create(lv_scr_act());lv_obj_set_pos(label_tem, 120, 50);                                    /*Set its position*/lv_obj_set_size(label_tem, 60, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_tem, lv_color_make(0xff, 0xff, 0xff), LV_PART_MAIN|LV_STATE_DEFAULT);//天气label_wea_img=lv_label_create(lv_scr_act());lv_obj_set_pos(label_wea_img, 10, 90);                                    /*Set its position*/lv_obj_set_size(label_wea_img, 160, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_wea_img, lv_color_make(0xff, 0xff, 0xff), LV_PART_MAIN|LV_STATE_DEFAULT);//湿度label_humidity=lv_label_create(lv_scr_act());lv_obj_set_pos(label_humidity, 80, 90);                                    /*Set its position*/lv_obj_set_size(label_humidity, 60, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_humidity, lv_color_make(0x00, 0xff, 0x00), LV_PART_MAIN|LV_STATE_DEFAULT);//日期label_date=lv_label_create(lv_scr_act());lv_obj_set_pos(label_date, 20, 130);                                    /*Set its position*/lv_obj_set_size(label_date, 170, 32);                                  /*Set its size*/lv_obj_set_style_text_color(label_date, lv_color_make(0x00, 0x00, 0xff), LV_PART_MAIN|LV_STATE_DEFAULT);ESP_LOGI(TAG, "LVGL interface init OK!");while (1){vTaskDelay(pdMS_TO_TICKS(1000));if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)){lv_timer_handler();xSemaphoreGive(xGuiSemaphore);}}free(buf1);free(buf2);vTaskDelete(NULL);
}

3、void custom_init(void)

建立queue处理TASK

建立定时,1个小时执行一次重新获取天气信息

执行exmple_connect(),连接WIFI

向queue模拟发送获得IP成功,触发queue下一步操作

void custom_init(void)
{ESP_ERROR_CHECK( nvs_flash_init() );ESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());ESP_ERROR_CHECK(example_connect());queue = xQueueCreate(1, 1024*2);xTaskCreate(queue_task, "queue task", 1024*6, NULL, 2, NULL);http_timers = xTimerCreate("http_timers", pdMS_TO_TICKS(1000), pdTRUE, 0, http_hour_requst_time);vTaskDelay(4000 / portTICK_PERIOD_MS);static char* queue_buff;queue_buff = pvPortMalloc(128);memset(queue_buff, 0, 128);sprintf(queue_buff, "{\"ip\":{\"IP\":\"%s\"}}","11.11.11.11");//前面example_connect()不可控,运行到这里应该已经获得ip了,向QUEUE模拟发送一个ip已经获得的消息,触发执行后面的程序xQueueSend(queue, queue_buff, portMAX_DELAY);vPortFree(queue_buff);
}

 4、static void queue_task(void* arg)

根据进入QUEUE的信息,执行不同的任务,一个守护task

static int cjson__analysis_type(char* json_data)
{cJSON* root = cJSON_Parse(json_data);//ESP_LOGI(TAG, "json_data:%s",json_data);if (root==NULL) {printf("[%s] is not json\r\n", __func__);return 0;}cJSON* wifi = cJSON_GetObjectItem(root, "WiFi");if (wifi) {cJSON_Delete(root);return 1;}cJSON* ip = cJSON_GetObjectItem(root, "ip");if (ip) {cJSON_Delete(root);return 2;}cJSON* weather = cJSON_GetObjectItem(root, "weather");if (weather) {cJSON_Delete(root);return 3;}cJSON_Delete(root);return 0;
}static void queue_task(void* arg)
{char* queue_buff = NULL;queue_buff = pvPortMalloc(1024*2);while (1){vTaskDelay(pdMS_TO_TICKS(100));memset(queue_buff, 0, 1024*2);xQueueReceive(queue, queue_buff, portMAX_DELAY);switch (cjson__analysis_type(queue_buff)){case 0:printf("queue_buff:%s\r\n",queue_buff);break;case 1: //wifibreak;case 2: //ipif (https_Handle!=NULL) {vTaskDelete(https_Handle);}xTaskCreate(&http_get_task, "http_get_task", 4096, NULL, 5, &https_Handle);break;case 3: //weathervTaskSuspend(https_Handle);cjson_get_weather(queue_buff);break;default:break;}}vPortFree(queue_buff);
}

5、static void http_hour_requst_time(TimerHandle_t timer),

每1个小时重新执行一次获取天气信息

static void http_hour_requst_time(TimerHandle_t timer)
{if (timers_http>=60*60) {//LOG_I("Timed to http update,start https request");vTaskResume(https_Handle);timers_http = 0;}else {timers_http++;}}

6、static void http_get_task(void *pvParameters)

向网站发送API获取信息,返回天气信息入QUEUE。

#define WEB_SERVER "v1.yiketianqi.com"
#define WEB_PORT "80"
#define WEB_PATH "/api?unescape=1&version=v61&appid=替换成自己的ID&appsecret=替换成自己的KEY"static const char *REQUEST = "GET " WEB_PATH " HTTP/1.0\r\n""Host: "WEB_SERVER":"WEB_PORT"\r\n""User-Agent: esp-idf/1.0 esp32\r\n""\r\n";static char* https_get_data(const char* https_request_data)
{char* request_data = https_request_data;printf("https_get_data:\r\n%s\r\n",request_data);static char* https_data;https_data = pvPortMalloc(1024*2);memset(https_data, 0, 1024*2);request_data += 2;char* date = pvPortMalloc(64);char* request_value = strtok(request_data, "\n");for (size_t i = 0; i < 13; i++){printf("[%d]%s\r\n", i,request_value);if (i==2) strcpy(date, request_value);if(i==12) strcpy(https_data, request_value);memset(request_value, 0, strlen(request_value));request_value = strtok(NULL, "\n");}vPortFree(date);return https_data;
}static void http_get_task(void *pvParameters)
{const struct addrinfo hints = {.ai_family = AF_INET,.ai_socktype = SOCK_STREAM,};struct addrinfo *res;struct in_addr *addr;int s, r;char recv_buf[64];static char* buff;char* queue_buff = NULL;buff = pvPortMalloc(2*1024);memset(buff, 0, 2*1024);while(1) {int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);if(err != 0 || res == NULL) {ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);vTaskDelay(1000 / portTICK_PERIOD_MS);continue;}/* Code to print the resolved IP.Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));s = socket(res->ai_family, res->ai_socktype, 0);if(s < 0) {ESP_LOGE(TAG, "... Failed to allocate socket.");freeaddrinfo(res);vTaskDelay(1000 / portTICK_PERIOD_MS);continue;}ESP_LOGI(TAG, "... allocated socket");if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);close(s);freeaddrinfo(res);vTaskDelay(4000 / portTICK_PERIOD_MS);continue;}ESP_LOGI(TAG, "... connected");freeaddrinfo(res);if (write(s, REQUEST, strlen(REQUEST)) < 0) {ESP_LOGE(TAG, "... socket send failed");close(s);vTaskDelay(4000 / portTICK_PERIOD_MS);continue;}ESP_LOGI(TAG, "... socket send success");struct timeval receiving_timeout;receiving_timeout.tv_sec = 5;receiving_timeout.tv_usec = 0;if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout,sizeof(receiving_timeout)) < 0) {ESP_LOGE(TAG, "... failed to set socket receiving timeout");close(s);vTaskDelay(4000 / portTICK_PERIOD_MS);continue;}ESP_LOGI(TAG, "... set socket receiving timeout success");/* Read HTTP response */do {bzero(recv_buf, sizeof(recv_buf));r = read(s, recv_buf, sizeof(recv_buf)-1);strncat(buff, recv_buf, r);     //for(int i = 0; i < r; i++) {putchar(recv_buf[i]);}} while(r > 0);ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d.", r, errno);close(s);queue_buff = pvPortMalloc(1024*3);memset(queue_buff, 0, 1024*3);sprintf(queue_buff, "{\"weather\":%s}", https_get_data(buff));xQueueSend(queue, queue_buff, portMAX_DELAY);xTimerStart(http_timers, portMAX_DELAY);vPortFree(buff);vTaskDelay(50/portTICK_PERIOD_MS);for(int countdown = 10; countdown >= 0; countdown--) {ESP_LOGI(TAG, "%d... ", countdown);vTaskDelay(1000 / portTICK_PERIOD_MS);}ESP_LOGI(TAG, "Starting again!");}}

7、void cjson_get_weather(char* weather_data)

处理json,并在LCD显示。

void cjson_get_weather(char* weather_data)
{cJSON * item = NULL;//cjson对象cJSON* root = cJSON_Parse(weather_data );root=   cJSON_GetObjectItem(root, "weather");if (!root){printf("Error before: [%s]\n",cJSON_GetErrorPtr());}else{item = cJSON_GetObjectItem(root, "cityEn");			//城市lv_label_set_text(label_city, item->valuestring);item = cJSON_GetObjectItem(root, "tem");			//温度lv_label_set_text(label_tem, item->valuestring);item = cJSON_GetObjectItem(root, "wea_img");			//wealv_label_set_text(label_wea_img, item->valuestring);item = cJSON_GetObjectItem(root, "humidity");			//wealv_label_set_text(label_humidity, item->valuestring);item = cJSON_GetObjectItem(root, "date");lv_label_set_text(label_date, item->valuestring);}cJSON_free(item);}

二、说明

1、利用了example中的example_connect()函数实现wifi连接,需要做一下配置:

CMakeLists.txt增加:

set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)

 idf.py menuconfig 设置SSID和password

2、生成的BIN大于1M,Partition Table中选择“Single factory app(large)”,可以支持到1.5M

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

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

相关文章

ES6之数值的扩展

1. 数值的扩展 1.1. 二进制和八进制字面量表示:1.2. 数值判断方法: 1.2.1. Number.isFinite() 检查一个值是否为有限的数值。1.2.2. Number.isNaN() 更准确地检测NaN值。1.2.3. 传统的全局方法 isFinite() 和 isNaN() 的区别 1.3. 数值转换方法:1.4. 整数检查与精度: 1.4.1. Nu…

防火墙技术基础篇:解析防火墙的网络隔离机制

防火墙技术基础篇&#xff1a;解析防火墙的网络隔离机制 网络安全在现代社会中扮演着重要的角色&#xff0c;保护网络系统、用户和数据免受未经授权的访问、破坏和窃取。个人、企业和国家都需要加强网络安全意识&#xff0c;采取有效措施保护自身的网络安全。随着网络攻击手段…

【QT八股文】系列之篇章2 | QT的信号与槽机制及通讯流程

【QT八股文】系列之篇章2 | QT的信号与槽机制及通讯流程 前言2. 信号与槽信号与槽机制介绍/本质/原理&#xff0c;什么是Qt信号与槽机制&#xff1f;如何在Qt中使用&#xff1f;信号与槽机制原理&#xff0c;解析流程Qt信号槽的调用流程信号与槽机制的优缺点信号与槽机制需要注…

深入分析 Android Activity (三)

深入分析 Android Activity (三) 1. Activity 的配置变化处理 当设备配置&#xff08;如屏幕方向、语言、屏幕大小等&#xff09;发生变化时&#xff0c;默认情况下&#xff0c;Android 会销毁并重新创建当前的 Activity。这种行为确保了新配置能够正确应用&#xff0c;但在某…

HTML5 性能优化和计算机硬件使用

目录 启用硬件加速图像与媒体优化资源加载与缓存CSS与布局优化JavaScript性能优化浏览器兼容性与特性检测启用硬件加速 Canvas绘图 <canvas> 元素支持硬件加速,可以显著提升图形绘制和动画的性能。确保在支持的浏览器中启用硬件加速,如使用translate3d(0, 0, 0) hack…

解锁Android高效数据传输的秘钥 - Parcelable剖析

作为Android开发者&#xff0c;我们经常需要在不同的组件(Activity、Service等)之间传输数据。这里的"传输"往往不仅仅是简单的数据复制&#xff0c;还可能涉及跨进程的内存复制操作。当传输的数据量较大时&#xff0c;这种操作可能会带来严重的性能问题。而Android系…

web自动化之PO模式

PO模式 1、为什么需要PO思想&#xff1f; 首先我们观察和思考一下&#xff0c;目前我们写的作业脚本的问题&#xff1a; 元素定位和操作动 作写到一起了&#xff0c;这就就会用导致一个问题&#xff1a; UI的页面元素比较容易变化的&#xff0c;所以元素定位和脚本操作写到一…

如何将照片从 iPhone 传输到闪存驱动器【无质量损坏】

概括 人们喜欢用 iPhone 拍照&#xff0c;因为照片通常都很漂亮&#xff0c;这都要归功于 iPhone 令人惊叹的技术。但照片更新后会占用更多空间&#xff0c;并且您可能会开始收到没有存储空间的通知。因此&#xff0c;您可以将照片传输到 USB 驱动器&#xff0c;然后从 iPhone…

Spring Boot构建mvc项目

好的,以下是一个简单的Java MVC(Model-View-Controller)项目示例,使用Spring Boot框架和MySQL数据库。这个项目包括基本的CRUD操作。 项目结构 src/ └── main/├── java/│ └── com/│ └── example/│ └── demo/│ ├──…

springboot-阿里羚羊 服务端埋点

官方文档 集成Java SDK 手动引入jar包「quickaplus-log-collector-java-sdk-1.0.1-SNAPSHOT.jar」 <dependency><groupId>com.alibaba.lingyang</groupId><artifactId>quickaplus-log-collector-java-sdk</artifactId><version>1.0.1&l…

应用案例 | 如何实时监测和管理冷链仓库温湿度?

一、项目背景 冷链仓库温湿度管理的重要性在于确保仓库内产品的质量和安全。通过遵循相关法规和标准&#xff0c;满足客户对产品质量的需求&#xff0c;同时实施有效的温湿度管理措施&#xff0c;可以降低成本并提高仓库作业效率。该项目的实施旨在帮助客户保证产品的新鲜度&a…

Java - AbstractQueuedSynchronizer

AQS简介 AQS全称AbstractQueuedSynchronizer&#xff0c;抽象队列同步器&#xff0c;是一个实现同步组件的基础框架。AQS使用一个int类型的成员变量state维护同步状态&#xff0c;通过内置的同步队列&#xff08;CLH锁、FIFO&#xff09;完成线程的排队工作&#xff0c;底层主…

echarts 散点图修改散点图中图形形状颜色大小

话不多说&#xff0c;直接上代码 let option {color:[xxx, xxx, xxx, xxx], //直接设置color可修改图形颜色title: {text: 散点图图形,},tooltip: {trigger: axis,axisPointer: {type: cross}},legend: {top: 2,right:2,itemWidth: 10,itemHeight: 10,textStyle:{fontSize:14}…

shell脚本条件语句和循环语句

文章目录 一、条件语句测试比较整数数值字符串比较逻辑运算双中括号&#xff08; &#xff09;{ }if语句结构case语句 二、循环语句基础知识for循环whileuntil双重循环及跳出循环 一、条件语句 测试 条件测试&#xff1a;判断某需求是否满足&#xff0c;需要由测试机制来实现…

视频分类——C3D使用

整体比较分散&#xff0c;可能很多源码都需要修改&#xff0c;需要有耐心。 一、数据准备 PS 调研后&#xff0c;上手容易代码比较简洁的是&#xff1a;https://github.com/Niki173/C3D/tree/main 因为源码很多参数都写死到了源码中&#xff0c;没有解耦&#xff0c;并且默…

CCF-CSP认证 2024年3月 4.化学方程式配平

题解&#xff1a;首先完成数据的读入&#xff0c;然后高斯消元求秩按题意解即可 #pragma GCC optimize(2, 3, "Ofast", "inline") #include <bits/stdc.h> using namespace std; const int maxn 100;using matrix double[maxn][maxn]; using vect…

5.20Git

版本控制工具Git&#xff0c;其他的工具还有SVN 共享代码&#xff0c;追溯记录&#xff0c;存储.c文件 Git实现的功能&#xff1a;回溯&#xff08;以前某个时间节点的数据情况&#xff09;共享&#xff08;大家共享修改&#xff09; Git&#xff1a;80% SVN&#xff…

QT tableWidget详细分析

一.定义 QTableWidget是一个用于显示表格数据的Qt控件&#xff0c;它是一个基于Qt Model/View框架的视图组件。QTableWidget提供了一种简单的方式来展示和编辑表格数据&#xff0c;用户可以通过添加行、列和单元格来构建一个完整的数据表格。 下面是一些QTableWidget的主要特点…

The Missing Semester of Your CS Education(计算机教育中缺失的一课)

Shell 工具和脚本(Shell Tools and Scripting) 一、shell脚本 1.1、变量赋值 在bash中为变量赋值的语法是foobar&#xff0c;访问变量中存储的数值&#xff0c;其语法为 $foo。 需要注意的是&#xff0c;foo bar &#xff08;使用空格隔开&#xff09;是不能正确工作的&…

网工内推 | 香港移动,10年以上数通经验,CCIE,5W-6W

01 香港移动招聘 &#x1f537;招聘岗位&#xff1a;网络工程师 &#x1f537;岗位要求&#xff1a; 需要有10年及以上数通经验&#xff0c;有CCIE 证书&#xff0c;懂技术管理&#xff0c;沟通畅通 &#x1f537;语言要求&#xff1a; 粤语英语 &#x1f537;薪资&#xff1…