• [技术干货] 【故障注入第十九期】Linux OS相关故障-文件系统(中期)
    大家好,这一期我们接上期内容,小编在整理材料过程中,发现分两期来讲,内容有点多,故分为上、中、下三期向大家介绍,这是第二期,一起继续学习如何使用DemonCAT注入文件系统方面的故障,还支持哪些场景,怎么操作呢?一起来看下吧。文件系统卸载挂死 所有文件卸载挂死 目录卸载忙文件丢失系统文件句柄耗尽文件损坏文件块损坏这一期关于DemonCAT注入文件系统故障方法我们就先介绍到这,下一期我们继续,敬请期待~
  • [技术干货] Linux驱动开发_倒车影像项目介绍[转载]
    原文链接:https://bbs.huaweicloud.com/blogs/353235倒车影像项目模拟: 汽车中控台---倒车影像。组成部分:1.​ LCD屏: 实时显示摄像头采集的数据。2.​ 摄像头: 放在车尾,采集图像传输给LCD屏进行显示。3.​ 倒车雷达: 超声波测距--->测量车尾距离障碍物的距离。4.​ 蜂鸣器: 根据倒车雷达测量的距离,控制频率。1.1 超声波测距模块声波测距: 已知声音在空气中传播的速度。​ 硬件接线:ECHO------->GPX1_0 (开发板第9个IO口): 中断引脚----->检测回波----输入TRIG ------->GPB_7 (开发板第8个IO口): 输出触发信号。1.2 PWM方波控制蜂鸣器​ PWM方波:​ 内核自带的PWM方波驱动1.3 UVC免驱摄像头编程框架: V4L2编程的框架: v4l2--->全称: video4linux2V4L2 : 针对UVC免驱USB设备设计框架。专用于USB摄像头的数据采集。免驱 : 驱动已经成为标准,属于内核自带源码的一部分。V4L2框架本身注册的也是字符设备,设备节点: /dev/videoXV4L2 框架: 提供ioctl接口,提供了有很多命令,可以通过这些命令对摄像头做配置。比如: 输出的图像尺寸,输出图像格式(RGB、YUV、JPG),申请采集数据的缓冲区。​ 配置摄像头采集队列步骤:Mmap函数映射。超声波驱动读取距离:#include <linux/kernel.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/timer.h> #include <linux/wait.h> #include <linux/sched.h> #include <linux/poll.h> #include <linux/fcntl.h> #include <linux/interrupt.h> #include <linux/ktime.h> static unsigned int distance_irq; /*存放中断号*/ static u32 *GPB_DAT=NULL; static u32 *GPB_CON=NULL; static u32 distance_time_us=0; /*表示距离的时间*/ /* 工作队列处理函数: */ static void distance_work_func(struct work_struct *work) { u32 time1,time2; time1=ktime_to_us(ktime_get()); /*获取当前时间,再转换为 us 单位*/ /*等待高电平时间结束*/ while(gpio_get_value(EXYNOS4_GPX1(0))){} time2=ktime_to_us(ktime_get()); /*获取当前时间,再转换为 us 单位*/ distance_time_us=time2-time1; //printk("us=%d\n",time2-time1); /*us/58=厘米*/ } /*静态方式初始化工作队列*/ static DECLARE_WORK(distance_work,distance_work_func); /* 中断处理函数: 用于检测超声波测距的回波 */ static irqreturn_t distance_handler(int irq, void *dev) { /*调度工作队列*/ schedule_work(&distance_work); return IRQ_HANDLED; } static void distance_function(unsigned long data); /*静态方式定义内核定时器*/ static DEFINE_TIMER(distance_timer,distance_function,0,0); /*内核定时器超时处理函数: 触发超声波发送方波*/ static void distance_function(unsigned long data) { static u8 state=0; state=!state; /*更改GPIO口电平*/ if(state) { *GPB_DAT|=1<<7; } else { *GPB_DAT&=~(1<<7); } /*修改定时器的超时时间*/ mod_timer(&distance_timer,jiffies+msecs_to_jiffies(100)); } static int distance_open(struct inode *inode, struct file *file) { return 0; } #define GET_US_TIME 0x45612 static long distance_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long argv) { u32 *us_data=(u32*)argv; int err; u32 time_us=distance_time_us; switch(cmd) { case GET_US_TIME: err=copy_to_user(us_data,&time_us,4); if(err!=0)printk("拷贝失败!\n"); break; } return 0; } static int distance_release(struct inode *inode, struct file *file) { return 0; } /*定义文件操作集合*/ static struct file_operations distance_fops= { .open=distance_open, .unlocked_ioctl=distance_unlocked_ioctl, .release=distance_release }; /*定义杂项设备结构体*/ static struct miscdevice distance_misc= { .minor=MISC_DYNAMIC_MINOR, .name="tiny4412_distance", .fops=&distance_fops }; static int __init tiny4412_distance_dev_init(void) { int err; /*1. 映射GPIO口地址*/ GPB_DAT=ioremap(0x11400044,4); GPB_CON=ioremap(0x11400040,4); *GPB_CON&=~(0xF<<4*7); *GPB_CON|=0x1<<4*7; /*配置输出模式*/ /*2. 根据GPIO口编号,获取中断号*/ distance_irq=gpio_to_irq(EXYNOS4_GPX1(0)); /*3. 注册中断*/ err=request_irq(distance_irq,distance_handler,IRQ_TYPE_EDGE_RISING,"distance_device",NULL); if(err!=0)printk("中断注册失败!\n"); else printk("中断:超声波测距驱动安装成功!\n"); /*4. 修改定时器超时时间*/ mod_timer(&distance_timer,jiffies+msecs_to_jiffies(100)); /*杂项设备注册*/ misc_register(&distance_misc); return 0; } static void __exit tiny4412_distance_dev_exit(void) { /*5. 注销中断*/ free_irq(distance_irq,NULL); /*6. 停止定时器*/ del_timer(&distance_timer); /*7. 取消IO映射*/ iounmap(GPB_DAT); iounmap(GPB_CON); /*注销杂项设备*/ misc_deregister(&distance_misc); printk("中断:超声波测距驱动卸载成功!\n"); } module_init(tiny4412_distance_dev_init); module_exit(tiny4412_distance_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("tiny4412 wbyq");摄像头代码,读取摄像头画面:#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <poll.h> #include <signal.h> #include <unistd.h> #include <fcntl.h> #include <poll.h> #include <signal.h> #include <pthread.h> #include <linux/videodev2.h> #include <stdlib.h> #include <sys/mman.h> #include <string.h> #include "framebuffer.h" #define PWM_DEVICE "/dev/pwm" /*PWM方波设备文件*/ #define DISTANCE_DEVICE "/dev/tiny4412_distance" /*超声波测距设备文件*/ #define UVC_VIDEO_DEVICE "/dev/video15" /*UVC摄像头设备节点*/ #define GET_US_TIME 0x45612 /*获取超声波测量的距离: ioctl命令*/ #define PWM_IOCTL_SET_FREQ 1 /*控制PWM方波频率: ioctl命令*/ #define PWM_IOCTL_STOP 0 /*停止PWM方波输出: ioctl命令*/ int distance_fd; /*超声波设备的文件描述符*/ int pwm_fd; /*PWM方波设备的文件描述符*/ int uvc_video_fd; /*UVC摄像头设备文件描述符*/ int Image_Width; /*图像的宽度*/ int Image_Height; /*图像的高度*/ unsigned char *video_memaddr_buffer[4]; /*存放摄像头映射到进程空间的缓冲区地址*/ /* 函数功能: 用户终止了进程调用 */ void exit_sighandler(int sig) { //停止PWM波形输出,关闭蜂鸣器 ioctl(pwm_fd,PWM_IOCTL_STOP,0); close(pwm_fd); close(distance_fd); exit(1); } /* 函数功能: 读取超声波数据的线程 */ void *distance_Getpthread_func(void *dev) { /*1. 打开PWM方波驱动*/ pwm_fd=open(PWM_DEVICE,O_RDWR); if(pwm_fd<0) //0 1 2 { printf("%s 设备文件打开失败\n",PWM_DEVICE); /*退出线程*/ pthread_exit(NULL); } /*2. 打开超声波测距设备*/ distance_fd=open(DISTANCE_DEVICE,O_RDWR); if(distance_fd<0) //0 1 2 { printf("%s 设备文件打开失败\n",DISTANCE_DEVICE); /*退出线程*/ pthread_exit(NULL); } /*3. 循环读取超声波测量的距离*/ struct pollfd fds; fds.fd=distance_fd; fds.events=POLLIN; int data; while(1) { poll(&fds,1,-1); ioctl(distance_fd,GET_US_TIME,&data); printf("距离(cm):%0.2f\n",data/58.0); data=data/58; if(data>200) /*200厘米: 安全区域*/ { //停止PWM波形输出,关闭蜂鸣器 ioctl(pwm_fd,PWM_IOCTL_STOP,0); } else if(data>100) /*100厘米: 警告区域*/ { printf("警告区域!\n"); ioctl(pwm_fd,PWM_IOCTL_SET_FREQ,2); } else /*小于<100厘米: 危险区域*/ { printf(" 危险区域!\n"); ioctl(pwm_fd,PWM_IOCTL_SET_FREQ,10); } //ioctl(pwm_fd,PWM_IOCTL_SET_FREQ,pwm_data); /*倒车影像: 测距有3个档位*/ } } /* 函数功能: UVC摄像头初始化 返回值: 0表示成功 */ int UVCvideoInit(void) { /*1. 打开摄像头设备*/ uvc_video_fd=open(UVC_VIDEO_DEVICE,O_RDWR); if(uvc_video_fd<0) { printf("%s 摄像头设备打开失败!\n",UVC_VIDEO_DEVICE); return -1; } /*2. 设置摄像头的属性*/ struct v4l2_format format; memset(&format,0,sizeof(struct v4l2_format)); format.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /*表示视频捕获设备*/ format.fmt.pix.width=800; /*预设的宽度*/ format.fmt.pix.height=480; /*预设的高度*/ format.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV; /*预设的格式*/ format.fmt.pix.field=V4L2_FIELD_ANY; /*系统自动设置: 帧属性*/ if(ioctl(uvc_video_fd,VIDIOC_S_FMT,&format)) /*设置摄像头的属性*/ { printf("摄像头格式设置失败!\n"); return -2; } Image_Width=format.fmt.pix.width; Image_Height=format.fmt.pix.height; printf("摄像头实际输出的图像尺寸:x=%d,y=%d\n",format.fmt.pix.width,format.fmt.pix.height); if(format.fmt.pix.pixelformat==V4L2_PIX_FMT_YUYV) { printf("当前摄像头支持YUV格式图像输出!\n"); } else { printf("当前摄像头不支持YUV格式图像输出!\n"); return -3; } /*3. 请求缓冲区: 申请摄像头数据采集的缓冲区*/ struct v4l2_requestbuffers req_buff; memset(&req_buff,0,sizeof(struct v4l2_requestbuffers)); req_buff.count=4; /*预设要申请4个缓冲区*/ req_buff.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /*视频捕获设备*/ req_buff.memory=V4L2_MEMORY_MMAP; /*支持mmap内存映射*/ if(ioctl(uvc_video_fd,VIDIOC_REQBUFS,&req_buff)) /*申请缓冲区*/ { printf("申请摄像头数据采集的缓冲区失败!\n"); return -4; } printf("摄像头缓冲区申请的数量: %d\n",req_buff.count); /*4. 获取缓冲区的详细信息: 地址,编号*/ struct v4l2_buffer buff_info; memset(&buff_info,0,sizeof(struct v4l2_buffer)); int i; for(i=0;i<req_buff.count;i++) { buff_info.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /*视频捕获设备*/ buff_info.memory=V4L2_MEMORY_MMAP; /*支持mmap内存映射*/ if(ioctl(uvc_video_fd,VIDIOC_QUERYBUF,&buff_info)) /*获取缓冲区的详细信息*/ { printf("获取缓冲区的详细信息失败!\n"); return -5; } /*根据摄像头申请缓冲区信息: 使用mmap函数将内核的地址映射到进程空间*/ video_memaddr_buffer[i]=mmap(NULL,buff_info.length,PROT_READ|PROT_WRITE,MAP_SHARED,uvc_video_fd,buff_info.m.offset); if(video_memaddr_buffer[i]==NULL) { printf("缓冲区映射失败!\n"); return -6; } } /*5. 将缓冲区放入采集队列*/ memset(&buff_info,0,sizeof(struct v4l2_buffer)); for(i=0;i<req_buff.count;i++) { buff_info.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /*视频捕获设备*/ buff_info.index=i; /*缓冲区的节点编号*/ buff_info.memory=V4L2_MEMORY_MMAP; /*支持mmap内存映射*/ if(ioctl(uvc_video_fd,VIDIOC_QBUF,&buff_info)) /*根据节点编号将缓冲区放入队列*/ { printf("根据节点编号将缓冲区放入队列失败!\n"); return -7; } } /*6. 启动摄像头数据采集*/ int Type=V4L2_BUF_TYPE_VIDEO_CAPTURE; if(ioctl(uvc_video_fd,VIDIOC_STREAMON,&Type)) { printf("启动摄像头数据采集失败!\n"); return -8; } return 0; } /* 函数功能: 将YUV数据转为RGB格式 函数参数: unsigned char *yuv_buffer: YUV源数据 unsigned char *rgb_buffer: 转换之后的RGB数据 int iWidth,int iHeight : 图像的宽度和高度 */ void yuv_to_rgb(unsigned char *yuv_buffer,unsigned char *rgb_buffer,int iWidth,int iHeight) { int x; int z=0; unsigned char *ptr = rgb_buffer; unsigned char *yuyv= yuv_buffer; for (x = 0; x < iWidth*iHeight; x++) { int r, g, b; int y, u, v; if (!z) y = yuyv[0] << 8; else y = yuyv[2] << 8; u = yuyv[1] - 128; v = yuyv[3] - 128; r = (y + (359 * v)) >> 8; g = (y - (88 * u) - (183 * v)) >> 8; b = (y + (454 * u)) >> 8; *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r); *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g); *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b); if(z++) { z = 0; yuyv += 4; } } } int main(int argc,char **argv) { int data; /*1. 注册将要捕获的信号*/ signal(SIGINT,exit_sighandler); /*2. 创建线程: 采集超声波测量的距离*/ pthread_t threadID; pthread_create(&threadID,NULL,distance_Getpthread_func,NULL); pthread_detach(threadID); //设置分离属性 /*3. 初始化摄像头*/ UVCvideoInit(); /*4. 初始化LCD屏*/ framebuffer_Device_init(); /*5. 循环采集摄像头的数据*/ struct pollfd fds; fds.fd=uvc_video_fd; fds.events=POLLIN; struct v4l2_buffer buff_info; memset(&buff_info,0,sizeof(struct v4l2_buffer)); int index=0; /*表示当前缓冲区的编号*/ unsigned char *rgb_buffer=NULL; /*申请空间:存放转换之后的RGB数据*/ rgb_buffer=malloc(Image_Width*Image_Height*3); if(rgb_buffer==NULL) { printf("RGB转换的缓冲区申请失败!\n"); exit(0); } while(1) { /*1. 等待摄像头采集数据*/ poll(&fds,1,-1); /*2. 取出一帧数据: 从采集队列里面取出一个缓冲区*/ buff_info.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /*视频捕获设备*/ ioctl(uvc_video_fd,VIDIOC_DQBUF,&buff_info); /*从采集队列取出缓冲区*/ index=buff_info.index; //printf("采集数据的缓冲区的编号:%d\n",index); /*3. 处理数据: YUV转RGB\显示到LCD屏*/ //video_memaddr_buffer[index]; /*当前存放数据的缓冲区地址*/ /*3.1 将YUV数据转为RGB格式*/ yuv_to_rgb(video_memaddr_buffer[index],rgb_buffer,Image_Width,Image_Height); /*3.2 将RGB数据实时刷新到LCD屏幕上*/ framebuffer_DisplayImages((800-Image_Width)/2,0,Image_Width,Image_Height,rgb_buffer); /*4. 将缓冲区再次放入采集队列*/ buff_info.memory=V4L2_MEMORY_MMAP; /*支持mmap内存映射*/ buff_info.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; /*视频捕获设备*/ buff_info.index=index; /*缓冲区的节点编号*/ ioctl(uvc_video_fd,VIDIOC_QBUF,&buff_info); /*根据节点编号将缓冲区放入队列*/ } return 0; }
  • [其他] Linux根目录利用率高,找不到占用空间文件
    **关键词:根目录满、根目录使用率高、根目录大文件找不到** 【现象】 巡检发现集群一个节点根目录占用率高,现场排查未能找到占用空间的文件。 【案例排查】 1. 集群节点根目录df –h,根目录878G占用643G,现场du计算大约有150g左右,大约有500g文件找不到。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20225/9/1652079031764904460.png) 2. 执行lsof | grep delete 查找被删除打开中的文件,发现/var/chroot/MRS/test_hf.log 文件大小534457784196/1024/1024/1024=497.75g,与期望文件大小相匹配。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20225/9/1652079386367311809.png) 3. 查看/var/chroot/MRS 路径发现log确实已经被删除。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20225/9/1652079689640261830.png) 4. 根据占用文件进程PID 8734找到对应进程,ps –ef | grep 8734,发现/opt/dws/tmp下一个.sh脚本运行中打开了log文件。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20225/9/1652079816162695142.png) 5. 查找对应的执行脚本,发现已被删除。 6. 在确认该脚本已无实际用途后,kill -9 8734,杀掉占用文件进程即可释放空间。 【根因】 1. 执行中脚本为死循环脚本,脚本被删除,生成log文件被删除,但未kill脚本进程。 2. 在linux中,当我们使用rm在linux上删除了大文件,但是,如果有进程打开了这个大文件,却没有关闭这个文件的句柄,那么:linux内核还是不会释放这个文件的磁盘空间,最后造成磁盘空间占用率高。
  • [技术干货] Linux系统下gcc命令使用详解
    大家好,本篇文章主要讲的是Linux系统下gcc命令使用详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览目录• 一.预处理 • 二. 编译 • 三.汇编 • 四.链接 1.gcc的安装(以Ubuntu为例) sudo apt-get install build-essential安装完后可以通过 gcc --version 查看版本。让我们在通过gcc编译可执行文件的过程中掌握其基础应用。准备: 先在当前目录下 使用vim新建一个.c文件 例如 666.c1$ vim 666.c(vim的使用可在我的另一篇博客有详细的叙述,这里不多在赘述)插入一段代码。12345678910#include <stdio.h>main(){    int a,i;    a=6;    for(i=0;i<3;i++)    {        printf("%d",a);    }}  (每次我们用 cat 查看)一.预处理1.预处理通过对宏定义(像#define)进行展开,对头文件(像 stdio.h)进行展开,对条件进行(像ifdef)编译,展开所有宏,删除所有注释(像"//").预处理cpp把源代码,头文件预编成一个.i文件。(注意这时并不检查语法,所以即使有语法错误也不会报错。)  2.命令:1$ gcc -E (源文件名) -o (预处理文件名)或者:1$ gcc (源文件名) > (预处理文件名)  例如按666.c 来说,预处理时可以是 :  gcc -E 666.c -o 666.i  也可以是 gcc 666.c > 666.i二. 编译   1.编译也就是检查语法是否错误,将预处理过的文件编译成汇编文件。   2.命令:1$ gcc -S (源文件) -o (汇编文件)  例如 gcc -S 666.i -o 666.s三.汇编1. 汇编也就是将汇编文件生成目标文件(二进制文件)通过汇编,文本代码变成了二进制代码。(二进制代码文件以.o为后缀名)。2.命令:1$ gcc -c (汇编文件) -o (目标文件)例如 gcc -c 666.s -o 666.o(这时候因为是二进制文件了,所以会乱码)四.链接1. 链接找到依赖的库文件(静态与动态),将目标文件链接为可执行程序。1$ gcc -c [目标文件] -o [可执行程序] -l[动态库名]假如没有动态库的话(一般)直接1$ gcc -c [目标文件] -o [可执行程序] 例如 gcc -c 666.o -o 666此时会生成可执行程序 666如果想执行使用该命令:1$ ./可执行程序其中./是在当前目录下的意思。例如 ./666(注意:在一般我们使用时 如果使用 gcc 可执行文件名,会默认生成a.out 可执行文件,这时我们直接执行它时用 ./a.out )转载自https://www.jb51.net/article/233584.htm
  • [技术干货] Linux系统中.bash_profile文件详解
    大家好,本篇文章主要讲的是Linux系统中.bash_profile文件详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览目录• 一. 环境变量$PATH: • 二. 修改环境变量: • 三.bash_profile的用途 •  总结 一. 环境变量$PATH:Linux是一个多用户操作系统,每个用户都有自己专有的运行环境。用户所使用的环境由一系列变量所定义,这些变量被称为环境变量。系统环境变量通常都是大写的。每个用户都可以根据需要修改自己的环境变量,以达到自己的使用要求。常见的环境变量如下表:在Shell下通过 美元符号$来引用环境变量,使用echo命令可以查看某个具体 环境变量的值。例如,查看PATH的值:1echo $PATH通过使用 env 或者 printenv 命令可以查看 系统全部 的环境变量 设置以下显示 env 命令的结果(局部):1234567TERM=xtermSHELL=/bin/bashUSER=leoPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/gamesHOME=/home/leoLANGUAGE=zh_CN:zh:en_US:enLOGNAME=leo二. 修改环境变量:登录用户可以根据需要修改和设置环境变量。Linux 下修改环境变量,既可以在终端通过 Shell 命令修改,也可以通过修改系统的配置文件来进行。2.1 修改系统配置文件(推荐)修改系统配置文件,可以达到永久改变环境变量的目的。修改某个配置文件后,在 Shell 下运行该文件即可使新的设置生效,或者重新登录使用新的变量。运行文件可用source 文件的方式操作,例如:1source ~/.bash_profile通常 修改 全局配置文件 /etc/profile 或者 用户配置文件 ~/.bashrc(有的发行版上为 ~/.bash_profile)文件:例如:1PATH=$PATH:$HOME/bin具体见解如下:$HOME这个代码是一个环境变量,它代表的是当前登录的用户的主文件夹的意思。(就是家目录的那个)$HOME/bin这个代码指的就是主文件夹下的bin子目录,代表的是文件夹的内部子目录。(注意不是根目录的那个)PATH=$PATH:$HOME/bin这个代码是设置PATH环境变量,设置环境变量用等号,:冒号是分割符。在Windows上添加环境变量用;分号分割,往后面追加。同理,在Mac上用:冒号分割,往后追加。$PATH:$HOME/bin表示在保留原来的$PATH环境变量的基础上,再增加$HOME/bin这个路径作为新的$PATH环境变量。计算机中的变量有许多,主要应用于系统文件的管理方面。注意:路径环境变量为PATH,但是引用的时候前面加一个$,即$PATH2.2 临时设置通过 Shell 命令设置 环境变量,常用于 临时设置 环境变量,一旦关闭当前终端或者新开一个终端,所设置的环境变量都将丢失。可以直接用 等号(=)为变量赋值,或者用 export 命令为变量赋值,用法:1变量 = $变量:新增变量值#方式1export 变量 = $变量:新增变量值#方式2例如:图片新增加的变量值既可以放在变量原有值的末尾( 变 量 : 新 增 变 量 值 ) , 也 可 以 放 在 原 有 变 量 值 的 开 头 ( 新 增 变 量 值 : 变量:新增变量值),也可以放在原有变量值的开头(新增变量值: 变量:新增变量值),也可以放在原有变量值的开头(新增变量值:变量)。三.bash_profile的用途在.bash_profile中常用于配置环境变量和用户一些自定义别名等, 总结到此这篇关于Linux系统中.bash_profile文件详解的文章就介绍到这了转载自https://www.jb51.net/article/233589.htm
  • [技术干货] Linux编译LVGL仿真器出错问题解决
    大家好,本篇文章主要讲的是Linux编译LVGL仿真器出错问题解决,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览目录• 一、错误现象 • 二、错误分析 • 三、错误解决 一、错误现象我在虚拟机下使用 LVGL 仿真器,编译仿真器源代码时发生报错1234567891011121314151617181920212223242526cc: error: unrecognized command line option ‘-Wshift-negative-value'cc: error: unrecognized command line option ‘-Wshift-negative-value'cc: error: unrecognized command line option ‘-Wshift-negative-value'Building project file: lvgl/examples/widgets/chart/lv_example_chart_6.cMakefile:45: recipe for target 'build/obj/lvgl/examples/widgets/list/lv_example_list_1.o' failedmake: *** [build/obj/lvgl/examples/widgets/list/lv_example_list_1.o] Error 1make: *** 正在等待未完成的任务....Makefile:45: recipe for target 'build/obj/lvgl/examples/widgets/spinner/lv_example_spinner_1.o' failedmake: *** [build/obj/lvgl/examples/widgets/spinner/lv_example_spinner_1.o] Error 1Makefile:45: recipe for target 'build/obj/lvgl/examples/widgets/led/lv_example_led_1.o' failedmake: *** [build/obj/lvgl/examples/widgets/led/lv_example_led_1.o] Error 1cc: error: unrecognized command line option ‘-Wshift-negative-value'Makefile:45: recipe for target 'build/obj/lvgl/examples/widgets/textarea/lv_example_textarea_3.o' failedmake: *** [build/obj/lvgl/examples/widgets/textarea/lv_example_textarea_3.o] Error 1cc: error: unrecognized command line option ‘-Wshift-negative-value'Makefile:45: recipe for target 'build/obj/lvgl/examples/widgets/textarea/lv_example_textarea_2.o' failedmake: *** [build/obj/lvgl/examples/widgets/textarea/lv_example_textarea_2.o] Error 1cc: error: unrecognized command line option ‘-Wshift-negative-value'cc: error: unrecognized command line option ‘-Wshift-negative-value'Makefile:45: recipe for target 'build/obj/lvgl/examples/widgets/textarea/lv_example_textarea_1.o' failedmake: *** [build/obj/lvgl/examples/widgets/textarea/lv_example_textarea_1.o] Error 1Makefile:45: recipe for target 'build/obj/lvgl/examples/widgets/checkbox/lv_example_checkbox_1.o' failedmake: *** [build/obj/lvgl/examples/widgets/checkbox/lv_example_checkbox_1.o] Error 1cc: error: unrecognized command line option ‘-Wshift-negative-value'Makefile:45: recipe for target 'build/obj/lvgl/examples/widgets/chart/lv_example_chart_6.o' failedmake: *** [build/obj/lvgl/examples/widgets/chart/lv_example_chart_6.o] Error 1编译无法进行二、错误分析根据提示分析错误,其中 cc: error 提示报错,翻到 Makefile 一看属于 gcc 编译器unrecognized command line option ‘-Wshift-negative-value’ 提示无法识别指令,所以分析应该是 GCC 版本的原因,可能我的版本不支持这个指令,解决的方式就是换版本,或者删掉这个指令看能不能正常运行三、错误解决这里我先试试删除指令再编译,先用 grep 找到指令在文件的哪一行1grep -n "\-Wshift\-negative\-value" Makefile编辑文件,删除对应指令1vim make file保存后程序编译编译成功,执行 demo,可以正常执行:转载自https://www.jb51.net/article/233714.htm
  • [技术干货] Linux和GNU系统的关系详解
    大家好,本篇文章主要讲的是Linux和GNU系统的关系详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览目录每天都在运行的Linux系统其实是?Linux内核 和 GNU 系统简介Linux内核 和 GNU 系统之间的关系详解总结每天都在运行的Linux系统其实是?今天广泛使用的 GNU 版本通常被称为“Linux”,而它的许多用户并不知道 它基本上是由GNU 项目开发的 GNU 系统 。Linux内核 和 GNU 系统简介确实有一个 Linux,这些人正在使用它,但它只是他们使用的系统的一部分。Linux 是内核:系统中的程序,它将机器的资源分配给您运行的其他程序。内核是操作系统的重要组成部分,但它本身毫无用处;它只能在完整操作系统的上下文中运行。Linux 通常与 GNU 操作系统结合使用:整个系统基本上是 GNU 加上 Linux,或 GNU/Linux。所有所谓的“Linux”发行版实际上都是 GNU/Linux 的发行版。许多用户不了解内核(Linux)与整个系统(他们也称为“Linux”)之间的区别。名称的模糊使用无助于人们理解。这些用户往往认为,Linus Torvalds 在 1991 年开发了整个操作系统,有一点帮助。Linux内核 和 GNU 系统之间的关系详解程序员一般都知道Linux是一个内核。但是,由于他们通常也听说过整个系统也被称为“Linux”,因此他们经常设想一段历史,可以证明以内核命名整个系统是合理的。例如,许多人认为,一旦 Linus Torvalds 完成 Linux 内核的编写,其用户就会四处寻找其他免费软件,并发现(无特殊原因)制作类 Unix 系统所需的大多数东西都已经可用的。他们的发现并非偶然——它是不完全完整的 GNU 系统。可用的自由软件加起来就是一个完整的系统,因为 GNU 项目自 1984 年以来就一直在努力制作一个。在GNU 宣言中,我们提出了开发一个自由的类 Unix 系统的目标,称为 GNU。GNU 项目的 初始公告还概述了 GNU 系统的一些原始计划。到 Linux 启动时,GNU 几乎完成了。大多数自由软件项目的目标是为特定工作开发特定程序。例如,Linus Torvalds 着手编写类 Unix 内核 (Linux);Donald Knuth 着手编写文本格式化程序 (TeX);Bob Scheifler 着手开发一个窗口系统(X Window System)。用来自项目的特定程序来衡量这种项目的贡献是很自然的。如果我们试图以这种方式衡量 GNU 项目的贡献,我们会得出什么结论?一家 CD-ROM 供应商发现,在他们的“Linux 发行版”中,GNU 软件是最大的单一队伍,约占总源代码的 28%,其中包括一些必不可少的主要组件,没有这些组件就没有系统。Linux 本身约占 3%。(2008 年的比例相似:在 gNewSense 的“主”存储库中,Linux 为 1.5%,GNU 软件包为 15%。)因此,如果您要根据谁在系统中编写程序来为系统选择一个名称,最合适的单一选择是“GNU”。但这并不是考虑这个问题的最深层次的方法。GNU 项目不是,也不是开发特定软件包的项目。这不是一个开发 C 编译器的项目,尽管我们这样做了。虽然我们开发了一个文本编辑器,但它不是一个开发文本编辑器的项目。GNU 计划着手开发一个完整的自由类 Unix 系统:GNU。许多人为系统中的自由软件做出了重大贡献,他们的软件都值得称赞。但它之所以是一个集成系统——而不仅仅是一组有用程序的集合——是因为 GNU 项目着手将它变成一个系统。我们列出了制作完整免费系统所需的程序清单,我们系统地查找、编写或找人编写清单上的所有内容。我们编写了必不可少但乏味的 [1]组件,因为没有它们您就无法拥有一个系统。我们的一些系统组件,即编程工具,自己在程序员中流行起来,但我们编写了许多不是工具的组件 [2]. 我们甚至开发了一个国际象棋游戏 GNU Chess,因为一个完整的系统也需要游戏。到 90 年代初,除了内核之外,我们已经将整个系统组装在一起。我们还启动了一个内核,即 GNU Hurd,它运行在 Mach 之上。开发这个内核比我们预期的要困难得多; GNU Hurd 于 2001 年开始可靠地工作,但距离让人们普遍使用还有很长的路要走。幸运的是,由于 Linux,我们不必等待 Hurd。Torvalds 在 1992 年解放了 Linux,它填补了 GNU 系统的最后一个主要缺口。然后人们可以 将 Linux 与 GNU 系统结合起来,形成一个完整的自由系统——一个也包含 Linux 的 GNU 系统版本。换句话说,GNU/Linux 系统。让他们很好地协同工作并非易事。一些 GNU 组件 [3]需要大量更改才能与 Linux 一起使用。将一个完整的系统集成为一个“开箱即用”的发行版也是一项艰巨的工作。它需要解决如何安装和引导系统的问题——我们还没有解决这个问题,因为我们还没有达到那个点。因此,开发各种系统发行版的人做了很多必不可少的工作。但是,就事物的性质而言,这是肯定会由某人完成的工作。GNU工程支持GNU / Linux系统,以及在GNU系统。该FSF资金的Linux相关的扩展,GNU C库的改写,所以,现在他们已完全融入,以及最新的GNU / Linux系统中使用当前版本的库没有变化。FSF 还资助了 Debian GNU/Linux 的早期开发阶段。今天有许多不同的 GNU/Linux 系统变体(通常称为“发行版”)。它们中的大多数都包含非自由程序——它们的开发人员遵循与 Linux 相关的“开源”哲学,而不是GNU的 “自由软件”哲学。但也有 完全免费的 GNU/Linux 发行版。FSF 支持其中一些的计算机设施。制作免费的 GNU/Linux 发行版不仅仅是消除各种非自由程序的问题。现在,通常的 Linux 版本也包含非自由程序。这些程序旨在在系统启动时加载到 I/O 设备中,它们以一长串数字的形式包含在 Linux 的“源代码”中。因此,维护免费的 GNU/Linux 发行版现在也需要维护Linux的免费版本。无论您是否使用 GNU/Linux,请不要混淆使用“Linux”这个名称来混淆公众。Linux 是内核,是系统必不可少的主要组件之一。整个系统基本上是GNU系统,加入了Linux。当您谈论这种组合时,请称其为“GNU/Linux”。
  • [技术干货] Zookeeper linux 服务端集群搭建步骤
    所需准备工作,创建三台虚拟机环境并安装好 java 开发工具包 JDK,可以使用 VM 或者 vagrant+virtualbox 搭建 centos/ubuntu 环境,本案例基于宿主机 windows10 系统同时使用 vagrant+virtualbox 搭建的 centos7 环境,如果直接使用云服务器或者物理机同理。骤一:准备三台 zookeeper 环境和并按照上一教程下载 zookeeper 压缩包,三台集群 centos 环境如下:机器一:192.168.3.33提示: 查看 ip 地址可以用 ifconfig 命令。步骤二:别修改 zoo.cfg 配置信息zookeeper 的三个端口作用1、2181 : 对 client 端提供服务2、2888 : 集群内机器通信使用3、3888 : 选举 leader 使用按 server.id = ip:port:port 修改集群配置文件:三台虚拟机 zoo.cfg 文件末尾添加配置:server.1=192.168.3.33:2888:3888server.2=192.168.3.35:2888:3888server.3=192.168.3.37:2888:3888根据 id 和对应的地址分别配置 myidvim /tmp/zookeeper/myid本案例配置完成后查询显示如下:IP 192.168.3.33 机器配置 myid,因为这台机器上个教程单机启动过,所以出现 version-2,没有也没关系。步骤三:启动集群启动前需要关闭防火墙(生产环境需要打开对应端口)systemctl stop firewalld启动 192.168.3.33 并查看日志,此时日志出现报错是正常现象,因为另外两台还没启动,暂时连接不上。另两台分别启动后,查看三台机器状态:IP 192.168.3.33IP 192.168.3.35最后显示集群搭建成功!Mode:leader 代表主节点,follower 代表从节点,一主二从。
  • [技术干货] (第四弹)我的前半生之----与代理机斗智斗勇的日子(部署Linux云主机篇)~
    序文:        我今年26岁,按理说还没有到七老八十,还没有到写回忆录的年纪。青葱岁月26载。闲暇之余,回首往事,发现好多曾经刻骨铭心的人和事,已经在念念不忘中渐渐遗忘了。刻不容缓,先记录一点是一点吧。                                                                    今早,确切地说,应该是今天早上起床后,我发现最近关于Devcloud之代理机部署的咨询问题剧烈突增,于是我心血来潮,踩在巨人的肩膀上,在官网帮助中心的优质文档的帮助下,实战搞定了这个问题,于是有了这篇帖子,以此纪念我那为了搭建实验环境而逝去的十几元代金券。下面,我将蓦然回首,追溯此事的来龙去脉。        首先描述一下我们为什么要配置代理机~:当我们只有少量公网IP或弹性公网IP的时候,我们需要在其他无公网IP的云服务器(也就是内网机器~)进行部署任务时,代理机的意义就此诞生!~下面我们不说废话,直接动手!1.首先我们购买2台以上的Linux云主机,至少要保证其中1台是绑定了弹性公网IP的,其余的机器在同一内网网段即可。(如果你有的话,也可以直接添加,无需新购。)把这台绑定了弹性公网IP的云主机,以代理机的形式添加进我们的部署任务所需要的主机组中,以下是截图参考:2.把我们的内网主机也依次添加进去,参考截图:3.耐心的等待连通性验证~ 验证成功后,我们具备了初步的部署环境4.此时我们去执行部署任务,把我们的构建包往主机里疯狂下载~ 哎呦我去,任务失败了,下载报错time out!超时了??什么鬼??连通性验证不是通过了吗??5.登录我们的内网机器,试着ping一下devcloud发布库服务的域名,看能否ping通,前文的”连通性验证成功”只能说明我们的代理机和内网机器是通的,而我们还需要确认下我们的内网机器能否访问到devcloud的发布库地址。 糟糕,不通!这是怎么回事?6.此刻的我表明强装镇定,内心十分慌张,擦掉额头上的冷汗,四处搜索解决方案,终于找到了原因~ 原来是没有购买NAT网关,没有配置SNAT规则导致~附上源文档:https://support.huaweicloud.com/usermanual-deployman/deployman_hlp_00039.html按文档购买并配置好我的SNAT网关~用时2分钟。7.回去重新测试一下能否ping通devcloud的发布库后台域名,哎呦?不用重新试了,在我添加好SNAT规则后,它已经自动连通了~PS:Devcloud服务是分区域的,每个区的域名都不一样~如果大家对主机组的安全性有要求,做了安全组策略,可以指定放行某一个区的IP白名单~并配置路由表。作者没有做类似的安全限制策略,只为验证内网主机能访问华为侧后台,所以随便ping一个区就可以了,这里我ping的是上海二区。8.赶快回去重新执行一下我的部署任务,疯狂下载、十分流畅~如何~?大咖们,你们的问题解决了嘛?!
  • [技术干货] 【故障注入第十八期】Linux OS相关故障-文件系统(上期)
    大家好,上一期关于DemonCAT工具使用及故障模式说明,我们介绍了进程方面的故障模式内容,本期我向大家介绍DemonCAT,关于文件系统的故障又是怎么来模拟的呢?文件系统故障又有哪些场景呢?但模拟文件系统的故障场景较多,所以分为上下两期,来向大家介绍,一起来学习下吧。磁盘满超大文件空间丢失文件不可删除文件/目录不可读写文件/目录不可读文件/目录不可写文件/目录不可重命名文件/目录死锁空文件全零文件破损文件好,本期关于DemonCAT,模拟文件系统的故障使用上期内容就先介绍到这里,下一期我们继续,敬请期待~
  • [技术干货] virtualbox网络配置
    一.设置virtualbox网卡1.1 关闭虚拟机1.2 设置添加网卡进入设置-网络1.2.1 添加网卡1(NAT网络)这个网络是主机通过网络地址转换到虚拟机,比如主机用无线网卡WLAN上网,用NAT转换比较合适,这样虚拟机也可以访问外网。1.2.2 添加网卡2(host only网络)这个网络是主机通过无线网卡WLAN上外网,但是虚拟机想通过有线网卡和主机、甚至与开发板互相ping通,传输文件。当然开启host only模式前先确保windows下的virtual host only网卡有开启,如下图:如果没有请按照下图操作:(这里是添加host only网卡)二,配置windows和虚拟机2.1 配置window以太网卡刚添加了虚拟机虚拟virtual host only网卡, 那么我们反正用的WLAN上的外网,为了方便,设置windows下的以太网卡网段和virtual host only网卡保持一致。2.2 配置虚拟机网络一般默认情况下,虚拟机是通过NAT共享网络给虚拟机用的,那么此时虚拟机也是可以上网的,只是不能和外界开发板进行互相ping, 同时windows主机也不能ping虚拟机。 如下图:图中可以看到两块网卡,enp0s3是Ubuntu默认的网卡(NAT),enp0s8是新增的网卡(host only),可以看到enp0s8还没有分配IP地址,我们需要手工指定一下。sudo vim /etc/network/interfaces将文件内容修改为如下所示:#interfaces(5) file used by ifup(8) and ifdown(8) auto lo iface lo inet loopback auto enp0s8 iface enp0s8 inet static address 192.168.56.101 netmask 255.255.255.0再来看下网卡ip信息:三,测试上网状态从测试结果上可以看到虚拟机上外网和ping windows主机都是ok的。 10.80.0.75时无线网卡的ip, 192.168.56.100是以太网卡的ip, 192.168.56.101是host only网卡的ip。同理用Windows ping虚拟机也是ok的。用开发板ping主机和虚拟机发现,只能ping通windows主机,无法ping通虚拟机,如下图。这是为什么呢?这是由于我们windows主机和开发板用的网线直连,两个以太网卡在同一网段下,当然能够ping通。但是虚拟机和windows主机用的确是host only网卡(NAT方式用来上外网),这样只能保证虚拟机和Windows主机是互通的,但是却无法被开发板访问,我们的开发板是没有无线网卡的,所以不能用WLAN,因此我们要想让开发板访问到虚拟机还得经过windows的以太网卡。那么我们虚拟机和windows主机是host only方式,所以我们无法用到以太网卡进行虚拟机和windows主机的交互。所以我们可以采取将host only网卡桥接到以太网卡,进入 网络-更改适配器-同时选中host only网卡和以太网卡,点击右键-选择桥接,如下图所示:这样我们的虚拟机的host only网卡就可以透过以太网卡和开发板交互了,效果如下:开发板能够ping windows主机和虚拟机。四,改进和优化如果不想在windows下进行host only网卡和以太网卡桥接,也可直接把virtualbox的第2路网卡由原来的host only修改成以太网卡桥接模式,如下:这样需要配置虚拟机的enp0s8网卡和windows主机的以太网卡网段保持一致的。(和前面2.2操作一样)4.1 windows ping 虚拟机4.2 虚拟机 ping windows4.3 开发板 ping windows和虚拟机
  • [技术干货] Linux-高级IO之select[转载]
    @TOC五种IO模型阻塞IO阻塞IO: 在内核将数据准备好之前, 系统调用会一直等待. 所有的套接字, 默认都是阻塞方式例如:A在钓鱼时,会一直盯着鱼漂,当鱼漂动时,拉动鱼竿,其余的时间都在盯着鱼漂。非阻塞IO非阻塞IO: 如果内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EWOULDBLOCK错误码非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符, 这个过程称为轮询. 这对CPU来说是较大的浪费, 一般只有特定场景下才使用。例如:B也来钓鱼,B一遍玩手机一遍看着鱼漂,还时不时的问A钓没钓到鱼。B不是一直在等还可以玩手机的等。信号驱动信号驱动IO: 内核将数据准备好的时候, 使用SIGIO信号通知应用程序进行IO操作例:此时C也来钓鱼,C将鱼竿上系了一个铃铛,C在看书,当铃铛响了C开始拉动鱼竿。C就像是信号驱动IO一样。多路转接IO多路转接: 虽然从流程图上看起来和阻塞IO类似. 实际上最核心在于IO多路转接能够同时等待多个文件描述符的就绪状态例:此时D拿着20根鱼竿来钓鱼,D来回看着就可以了。20根鱼竿鱼上钩的几率远大于之前的3个人。异步IO异步IO: 由内核在数据拷贝完成时, 通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据).例:E带着手下来钓鱼,E说:你在这钓,把桶钓满了拿回来给我。E然后开车走了。E根本不用在这里等待。总结:任何IO都包括2个步骤:1是等,2是拷贝读IO=等待读事件就绪+内核数据拷贝到用户空间写IO=等待写事件就绪+用户空间数据拷贝到内核空间高级IO的本质:尽可能减少等的时间比重同步和异步通信同步概念:所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回. 但是一旦调用返回,就得到返回值了; 换句话说,就是由调用者主动等待这个调用的结果异步概念:异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果; 换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果; 而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用还需注意多进程和多线程同步和异步之间的区别:进程/线程同步也是进程/线程之间直接的制约关系是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系. 尤其是在访问临界资源的时候。I/O多路转接之select系统提供select函数来实现多路复用输入/输出模型.select系统调用是用来让我们的程序监视多个文件描述符的状态变化的程序会停在select这里等待,直到被监视的文件描述符有一个或多个发生了状态改变select函数原型参数说明:参数nfds是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合;参数timeout为结构timeval,用来设置select()的等待时间参数timeout取值:NULL:则表示select()没有timeout,select将一直被阻塞,直到某个文件描述符上发生了件;0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。fd_set结构用命令vim /usr/include/sys/select.h查看源码:select的过程:简单的select服务器将创建套接字单独封装成一个类Sock.hppselectServer.hppselect.cc下面来测试一下:在用手机测试一下:总结select就绪条件读就绪socket内核中, 接收缓冲区中的字节数, 大于等于低水位标记SO_RCVLOWAT. 此时可以无阻塞的读该文件描述符, 并且返回值大于0;socket TCP通信中, 对端关闭连接, 此时对该socket读, 则返回0;监听的socket上有新的连接请求;socket上有未处理的错误写就绪socket内核中, 发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小), 大于等于低水位标记SO_SNDLOWAT, 此时可以无阻塞的写, 并且返回值大于0socket的写操作被关闭(close或者shutdown). 对一个写操作被关闭的socket进行写操作, 会触发SIGPIPE信号;socket使用非阻塞connect连接成功或失败之后;socket上有未读取的错误;select特点可监控的文件描述符个数取决与sizeof(fd_set)的值.服务器上sizeof(fd_set)=512,每bit表示一个文件描述符,则服务器上支持的最大文件描述符是512*8=4096.将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd,一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个参数。select缺点每次调用select, 都需要手动设置fd集合, 从接口使用角度来说也非常不便.每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大select支持的文件描述符数量太小本篇文章到这就结束了,后面还会有poll,epoll的讲解。
  • [问题求助] 申请mirror 企业级社区操作系统 Circle Linux
    项目名称与简介 (Project introduction)名称: CircleLinux介绍如下:Circle Linux 是国际化社区驱动的开源软件,使命在与努力专注于围绕 Linux 平台提供更强大的开源生态。提供企业级、生产环境就绪的 Linux 发行版。Global Community-driven Opensource software effort focus on delivering a robust open source ecosystem around a Linux platform.bring you Enterprise-grade, Production-ready Linux Distro.官网:www.cclinux.orgGitHub:https://github.com/circle-linux上游地址与镜像方法 (How to mirror)rsync -avh rsync://msync.cclinux.org/circle/pub/ . 镜像大小 (Mirror size)目前是400G,建议预留,随着全新版本的发布容量随之可能会到600G左右。备注 (Note)非常感谢你们提供的镜像服务,希望可以早日使用华为mirrors 提供的CircleLinux的Mirror 。Best Regards !以下是一些详细介绍和近期的进展:Circle Linux是扮演了昔日CentOS的角色。 CircleLinux企业级OS社区简况:社区官网 www.cclinux.orgGit仓库 git.cclinux.orgYUM源 mirror.cclinux.orgBuild系统 koji.cclinux.org社区论坛 talk.cclinux.orgwiki系统 wiki.cclinux.org国内mirrors:mirrors.tencent.com/circlemirrors.aliyun.com/circle国际mirrors:mirrors.xtom.de/circle网易163 mirrors 正在同步...您好 华为开源mirrors, 目前已有三家云厂商添加,辛苦华为云mirrors添加,非常感谢。
  • [技术干货] awk脚本统计一组单词中字母出现最多最少频率
    编写一个 awk 脚本来找到一组单词中出现次数最多(和最少)的单词。近一段时间,我开始编写一个小游戏,在这个小游戏里,玩家使用一个个字母块来组成单词。编写这个游戏之前,我需要先知道常见英文单词中每个字母的使用频率,这样一来,我就可以找到一组更有用的字母块。字母频次统计在很多地方都有相关讨论,包括在 维基百科 上,但我还是想要自己来实现。Linux 系统在 /usr/share/dict/words 文件中提供了一个单词列表,所以我已经有了一个现成的单词列表。然而,尽管这个 words 文件包含了很多我想要的单词,却也包含了一些我不想要的。我想要的单词首先不能是复合词(即不包含连接符和空格的单词),也不能是专有名词(即不包含大写字母单词)。为了得到这个结果,我可以运行 grep 命令来取出只由小写字母组成的行:$ grep  '^[a-z]*$' /usr/share/dict/words这个正则表达式的作用是让 grep 去匹配仅包含小写字母的行。表达式中的字符 ^ 和 $ 分别代表了这一行的开始和结束。[a-z] 分组仅匹配从 “a” 到 “z” 的小写字母。$ grep  '^[a-z]*$' /usr/share/dict/words | headaaaaaaaahaahedaahingaahs没错,这些都是合法的单词。比如,“aahed” 是 “aah” 的过去式,表示在放松时的感叹,而 “aalii” 是一种浓密的热带灌木。现在我只需要编写一个 gawk 脚本来统计出单词中各个字母出现的次数,然后打印出每个字母的相对频率。一种使用 gawk 来统计字母个数的方式是,遍历每行输入中的每一个字符,然后对 “a” 到 “z” 之间的每个字母进行计数。substr 函数会返回一个给定长度的子串,它可以只包含一个字符,也可以是更长的字符串。比如,下面的示例代码能够取到输入中的每一个字符 c:{    len = length($0); for (i = 1; i <= len; i++) {        c = substr($0, i, 1);    }}如果使用一个全局字符串变量 LETTERS 来存储字母表,我就可以借助 index 函数来找到某个字符在字母表中的位置。我将扩展 gawk 代码示例,让它在输入数据中只取范围在 “a” 到 “z” 的字母:BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" }{    len = length($0); for (i = 1; i <= len; i++) {        c = substr($0, i, 1);        ltr = index(LETTERS, c);    }}需要注意的是,index 函数将返回字母在 LETTERS 字符串中首次出现的位置,第一个位置返回 1,如果没有找到则返回 0。如果我有一个大小为 26 的数组,我就可以利用这个数组来统计每个字母出现的次数。我将在下面的示例代码中添加这个功能,每当一个字母出现在输入中,我就让它对应的数组元素值增加 1(使用 ++):BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" }{    len = length($0); for (i = 1; i <= len; i++) {        c = substr($0, i, 1);        ltr = index(LETTERS, c);         if (ltr &gt; 0) {            ++count[ltr];        }    }}当 gawk 脚本统计完所有的字母后,我希望它能输出每个字母的频率。毕竟,我对输入中各个字母的个数没有兴趣,我更关心它们的 相对频率。我将先统计字母 “a” 的个数,然后把它和剩余 “b” 到 “z” 字母的个数比较:END {    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {        if (count[ltr] < min) {            min = count[ltr];        }    }}在循环的最后,变量 min 会等于最少的出现次数,我可以把它为基准,为字母的个数设定一个参照值,然后计算打印出每个字母的相对频率。比如,如果出现次数最少的字母是 “q”,那么 min 就会等于 “q” 的出现次数。接下来,我会遍历每个字母,打印出它和它的相对频率。我通过把每个字母的个数都除以 min 的方式来计算出它的相对频率,这意味着出现次数最少的字母的相对频率是 1。如果另一个字母出现的次数恰好是最少次数的两倍,那么这个字母的相对频率就是 2。我只关心整数,所以 2.1 和 2.9 对我来说是一样的(都是 2)。END {    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {        if (count[ltr] < min) {            min = count[ltr];        }    }    for (ltr = 1; ltr <= 26; ltr++) {        print substr(LETTERS, ltr, 1), int(count[ltr] / min);    }}#!/usr/bin/gawk -f# 只统计 a-z 的字符,忽略 A-Z 和其他的字符BEGIN { LETTERS = "abcdefghijklmnopqrstuvwxyz" }{    len = length($0); for (i = 1; i <= len; i++) {        c = substr($0, i, 1);        ltr = index(LETTERS, c);        if (ltr < 0) {            ++count[ltr];        }    }}# 打印每个字符的相对频率END {    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {        if (count[ltr] < min) {            min = count[ltr];        }    }    for (ltr = 1; ltr <= 26; ltr++) {        print substr(LETTERS, ltr, 1), int(count[ltr] / min);    }}我将把这段程序保存到名为 letter-freq.awk 的文件中,这样一来,我就可以在命令行中更方便地使用它。如果你愿意的话,你也可以使用 chmod +x 命令把这个文件设为可独立执行。第一行中的 #!/usr/bin/gawk -f 表示 Linux 会使用 /usr/bin/gawk 把这个文件当作一个脚本来运行。由于 gawk 命令行使用 -f 来指定它要运行的脚本文件名,你需要在末尾加上 -f。如此一来,当你在 shell 中执行 letter-freq.awk,它会被解释为 /usr/bin/gawk -f letter-freq.awk。接下来我将用几个简单的输入来测试这个脚本。比如,如果我给我的 gawk 脚本输入整个字母表,每个字母的相对频率都应该是 1:
  • [技术干货] linux下直接拷贝新版本R的方法
    如果要使用新版本的R,除了直接安装,也可以直接拷贝R的文件夹。这样既可以保留原始的R版本和R包,也可以使用新版本的R和R包,R包存放在R目录下的library文件夹。文件放路径R: /usr/lib64/Rllibrary: 系统R library目录:/usr/lib64/R/library ;个人家目录下默认的R library目录:~/R/x86_64-pc-linux-gnu-library/3.2,最后一个是R版本号拷贝后的操作将新版本R拷贝过来后,进入R/bin/,编辑R文件,将HOME_DIR路径改为你当前的新的R路径并保存。此时可正常运行当前路径R。此时已经可以加载该R版本library文件夹下的R包,如果要添加新的R包,只需要将别的同R版本的R包文件夹比如data.table文件夹移动到新版本R包文件夹目录即可。
总条数:1204 到第 页
上滑加载中