Linux学习

Linux命令学习

注意点

  1. Linux中区分大小写
  2. Linux中正斜杠/表示目录

Linux的终端窗口

  • $表示Shell提示符(普通用户)
    作用:用户可以在提示符后输入带有选项和参数的字符命令,并能够在终端窗口中看到命令的运行结果,此后,将会出现一个新的提示符,标志着新命令行的开始
  • #表示Shell提示符(超级管理员)
    作用:权限更高,可以执行更多操作
  • Tab键可以自动匹配并补全命令
    作用:按Tab键时,如果系统只找到一个和输入字符相匹配的目录或文件,则自动补齐;如果没有匹配的内容或有多个相匹配的名字,系统将发出警鸣声,再按一下Tab键将列出所有相匹配的内容,以供用户选择
  • 上下键可以翻阅浏览历史
  • &可以使命令在后台执行,执行的命令后跟上一个“&”符号即可
find / -name httpd.conf &
  • 可以让多条命令在同一行执行
cd /;ls

文件目录类命令

  1. 浏览目录
  • pwd:用于显示用户当前所在的目录。如果用户不知道自己当前所处的目录,就可以使用这个命令获得当前所在目录。
  • cd:切换目录
cd            //切换至用户登录时的工作目录,一般Linux用终端打开时是该目录下
cd dir1     // 切换至当前目录下的dir1子目录下
cd ~         //切换至用户登录时的工作目录(用户的家目录)
cd ..         //切换至当前目录的父目录(也就是上一级目录)
cd ../user        //切换至当前目录的父目录的user子目录(也就是切换上一级目录后再去user子目录)
cd /dir1/subdir1    //利用绝对路径表示改变到/dir1/subdir1目录下
  1. 浏览文件
  • ls:列出文件和目录(list)
ls -a          //列出包括以.开始的隐藏文件在内的所有文件
ls -t           //依照文件最后修改时间的顺序(time)列出文件
ls -F          //列出当前目录下的文件名及其类型。以`/`结尾表示为目录名,以`*`为结尾表示可执行文件,以`@`结尾表示为符号连接
ls -l           //列出当前目录下所有文件的权限、所有者、文件大小、修改时间及名称
ls -lg         //同上,并显示出文件的所有者工作路径
ls -R         //显示出目录下以及其所有子目录的文件名
  • cat:用于连接文件并打印到标准输出设备上(concatenate)
cat -n textfile1 > textfile2     //把 textfile1 的文档内容加上行号后输入 textfile2 这个文档里
cat -b textfile1 textfile2 >> textfile3  //把 textfile1 和 textfile2 的文档内容加上行号(空白行不加)之后将内容附加到 textfile3 文档里

注意:>表示覆盖原文件,>>表示追加在原文件后面

  • more:显示更多内容
    作用:使用cat命令时,如果文件太长,用户只能看到文件的最后一部分。这时可以使用more命令,一页一页的分屏显示文件的内容。
    按【Enter】键可以向下移动一行,按【space】键可以向下移动一页;按【q】键可以退出more命令。
more  [+num/-num]  文件名
//+num表示从文件的第num行开始显示
//-num表示指定分页显示时每页的行数
  • less:less命令是more命令的改进版,比more命令的功能强大。more命令只能向下翻页,而less命令可以向下、向上翻页,甚至可以前后左右的移动。
    特殊: less命令还支持在一个文本文件中进行快速查找。先按下斜杠键【/】,再输入要查找的单词或字符。less命令会在文本文件中进行快速查找,并把找到的第一个搜素目标高亮度显示。如果希望继续查找,就再次按下斜杠键【/】,再按【Enter】键即可。
  • head:head命令用于显示文件的开头部分,默认情况下只显示文件的前10行内容。
head  [参数]  文件名 
//参数:
//-n num:显示指定文件的前num行。
//-c num:显示指定文件的前num个字符。
  • tail:tail命令用于显示文件的末尾部分,默认情况下只显示文件的末尾10行内容。
tail  [参数]  文件名
//参数:
//-n num:显示指定文件的末尾num行。
//-c num:显示指定文件的末尾num个字符。
//+num:从第num行开始显示指定文件的内容。
  1. 目录操作
  • mkdir:创建目录
  • rmdir:删除目录
  1. 文件操作
  • cp:复制文件
  • mv:用于文件或目录的移动或改名
  • rm:删除目录或文件
rm  [参数]  文件名或目录名 
//参数:
//-i:删除文件或目录时提示用户。
//-f:删除文件或目录时不提示用户。
//-R:递归删除目录,即包含目录下的文件和各级子目录。 
  • touch:修改文件的存取和修改时间为当前时间,有时候也可以建立空白文件
  • diff:比较两个文件不同的内容
  • ln:建立两个文件之间的链接关系
ln  [参数]  源文件或目录   链接名
//参数:
//-s:建立符号链接(软链接),不加该参数时建立的链接为硬链接。

注意:两个文件之间的链接关系有两种:一种称为硬链接,这时两个文件名指向的是硬盘上的同一块存储空间,对两个文件中的任何一个文件的内容进行修改都会影响到另一文件。它可以由ln命令不加任何参数建立。

  • tar:把一系列的文件归档到一个大文件中,也可以把档案文件解开以恢复数据。(建议相对路径打包)
tar [参数]  档案文件  文件列表
//-c:生成档案文件。
//-v:列出归档解档的详细过程。
//-f:指定档案文件名称。
//-r:将文件追加到档案文件末尾。
//-z:以gzip格式压缩或解压缩文件。
//-j:以bzip2格式压缩或解压缩文件。-a xz格式
//-d:比较档案与当前目录中的文件。
//-x:解开档案文件。 
  • xz:压缩或解压文件
//1.压缩文件
xz test.txt
//2.解压文件
xz -d test.txt.xz
  • whereis:用来寻找命令的可执行文件所在的位置;也可以用来获取命令简介
  • find:用于文件的查找
find  [路径]   [匹配表达式]

find命令的匹配表达式主要有以下几种类型。
-name filename:查找指定名称的文件。
-user username:查找属于指定用户的文件。
-group grpname:查找属于指定组的文件。
-print:显示查找结果。
-size n:查找大小为n块的文件,一块为512B。符号“+n”表示查找大小大于n块的文件;符号“-n”表示查找大小小于n块的文件;符号“nc”表示查找大小为n个字符的文件。
-inum n:查找索引节点号为n的文件。
-type:查找指定类型的文件。文件类型有:b(块设备文件)、c(字符设备文件)、d(目录)、p(管道文件)、l(符号链接文件)、f(普通文件)。
-atime n:查找n天前被访问过的文件。“+n”表示超过n天前被访问的文件;“-n”表示未超过n天前被访问的文件。
-mtime n:类似于atime,但检查的是文件内容被修改的时间。

下载软件的三种形式

  1. apt命令
  2. dpkg(.deb)
  3. 软件源(/etc/apt/sources.list)

如何在linux上安装和配置Apache服务器

安装

  1. 在桌面创建一个文件夹,例如我创建的是ccweb.com,右键通过终端打开
  2. 更新系统存储库:sudo apt update
  3. 使用apt命令安装Apache:sudo apt install apache2
  4. 检查安装:apache2 -version
    在这里插入图片描述

配置UFW防火墙

  1. 列出UFW应用程序配置文件:udo ufw app list
    在这里插入图片描述
  2. 在UFW上允许Apache并验证其状态:
    sudo ufw allow 'Apache'更新防火墙规则
    sudo ufw status展示防火墙状态
    在这里插入图片描述

如何在Ubuntu上安装和配置Apache2 web服务器

教程(要用电脑打开):如何在Ubuntu18.04上安装和配置Apache2 web服务器
笔者注:我用这个教程在Ubuntu22.04上安装和配置也可以成功,但是由于个人原因遇到了一些问题

  1. 输入域名的时候字母打错了,导致配置文件内的信息不正确。
    解决:再改一遍配置文件,并把不正确的域名可以反推通过下面的命令进行禁用,后面的配置文件可以更换为自己的
sudo a2dissite xxx.com.conf
  1. 需要做ip地址和域名的映射(如果您已购买域名则不用)
hostname -I
//查看本机地址
sudo nano /etc/hosts
//通过nano编辑器打开配置文件
//在文件末尾添加
本机地址  域名

注意

  1. 域名是http或https后面的部分,例如我设置的网页是http://www.xx.com,那么我此处配置的域名就是www.xx.com
  2. ip地址会随时变化,有时登录不进去可以查看ip地址是否变化,然后改一下映射

如何在Ubuntu上安装Hadoop

教程:Hadoop安装教程_单机/伪分布式配置_Hadoop2.6.0(2.7.1)/Ubuntu14.04(16.04)
遇到的一些问题:

  1. 创建hadoop用户之后要重启,登录到hadoop用户里面完成接下来的操作(命令行切换用户应该也可以,但我没试过)
  2. 安装java环境时要将添加的环境变量放在文件开始位置,可能是避免依赖问题或者防止覆盖
  3. 官网安装hadoop3太慢,在清华镜像网站下载:hadoop-3.4.0.tar.gz
  4. 通过jbs命令查看进程全部启动但是网站打不开:
  • 首先查看防火墙的设置,尝试关闭防火墙
  • 换一个端口,hadoop端口变化(50700-9870),hadoop3是9870端口可以进,hadoop2是50700

如何使用vim编辑器

esc键进入命令模式

  • shift + O :进入编辑模式
  • shift + :+ wq:保存并退出

Apache简单配置SSL的方法(Ubuntu20.04+HTTPS)

教程:Apache简单配置SSL的方法(Ubuntu20.04+HTTPS)
遇到了以下问题:

  1. 打开的conf文件是空白的,原因是原教程的复制的路径的最后的文件少了个.conf的后缀,导致打开的文件和复制的文件不对应

  2. 证书中的信息注解中的主机名要通过hostname查看在这里插入图片描述4. 教程中需要修改三个配置文件(三个配置文件相联系,我这个是可行的一种)

  • 端口配置文件/etc/apache2/ports.conf
sudo gedit /etc/apache2/ports.conf

在这里插入图片描述

  • 自己的虚拟主机配置文件/etc/apache2/sites-available/xxx.com.conf
    虚拟主机端口号为80(默认的HTTP端口),注意这里不可以是443,否则会无法建立安全连接。
    原因是:如果多个虚拟主机配置为监听同一端口(在本例中是443),你需要确保Web服务器配置能够区分它们,通常是通过ServerName或ServerAlias指令。也就是因为我设置的这两个指令相同,如果端口号一样,则会产生冲突
sudo gedit /etc/apache2/sites-available/xxx.com.conf
sudo a2enmod rewrite  //为重定向作准备
<VirtualHost *:80>
ServerAdmin admin@xxx.com  #服务器管理员的邮箱
ServerName xxx.com      #虚拟主机的主机名
ServerAlias www.xxx.com   #服务器别名,除了xxx.com,www.xxx.com也会解析这个虚拟主机
DocumentRoot /var/www/xxx.com/html  #该虚拟主机的文档根目录
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
//http重定向到https
RewriteEngine On  #启动重写引擎
RewriteCond %{HTTPS} !=on   #匹配所有非HTTTPS请求
RewriteRule ^(.*) https://%{SERVER_NAME}$1 [L,R]
</VirtualHost>
  • ssl配置文件/etc/apache2/sites-enabled/default-ssl.conf
    除了教程中后面需要改的,前面还需要加三行,端口号用443
sudo cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-enabled/default-ssl.conf
 
gedit /etc/apache2/sites-enabled/default-ssl.conf
ServerAdmin xxx@xxx.com
ServerName    xxx.com
DocumentRoot /var/www/xxx.com/html

在这里插入图片描述
4. 配置完https后在重启之前要启动ssl

sudo apt-get install openssl  //安装openssl
sudo a2enmod ssl    //启动ssl
sudo systemctl restart apache2  //重启apache2服务

5.通过https://www.xxx.com/测试访问是否成功,此时的域名对应的是/etc/hosts文件中ip地址对应的域名

如何实现网络通信编程

网络通信编程:客户端和服务端之间传递信息
这一块与计算机网络联系较大,等我把计网弄清楚再来补这个坑

如何增加系统调用(System Call)

Q:Linux系统调用是‌什么?
A:是操作系统内核(内核,是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能,是操作系统工作的基础,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性)提供给‌应用程序使用的一种服务接口,用于实现应用程序与操作系统内核之间的交互。 系统调用允许应用程序请求操作系统完成某些特定的操作,如‌文件操作、‌进程管理、‌设备访问等。这些操作通常涉及到底层的硬件资源,因此需要内核的参与和协调。‌

步骤(以编写一个自己的系统调用并在日志文件中查看相应打印信息为例)

1.假设我们原来的内核是linux-6.5.0,新编译了内核linux-6.8.6(也就是本机有两个内核版本)
2.在引导界面进入linux-6.5.0版本
注:这里进入新内核应该也没关系,但是我的新内核很卡,所以我选择进入旧内核
3.编辑系统调用入口表(一张由指向实现各种系统调用的内核函数的函数指针组成的表,该表可以基于系统调用编号进行索引,来定位函数地址,完成系统调用。)

sudo gedit /usr/src/linux-6.8.6/arch/x86/entry/syscalls/syscall_64.tbl

在这里插入图片描述
注:386表示第386行,463是系统调用号(一般按顺序写就可以,这里是跳过了一个,不影响),mysyscall是系统调用名,sys_mysyscall是以sys开头的系统调用函数名称
4.添加系统调用函数声明(这里根据C语言规则里面的先声明再调用)

cd /usr/src/linux-6.8.6
sudo gedit include/linux/syscalls.h #添加系统调用函数声明

在这里插入图片描述asmlinkage是GCC的一个宏定义,‌用于指示编译器函数参数不应通过寄存器传递,‌而应通过CPU的堆栈传递。‌这里可以根据syscalls.h中同样以sys开头的函数名的函数命名规则推断

5.编写系统调用的函数定义同时传入自定义的系统调用名(简单来说就是编写系统调用时你想实现的功能,这里的功能是打印)

sudo gedit kernel/sys.c 

在这里插入图片描述
6.修改完之后要再编译一次内核

cd  /usr/src/linux-6.8.6
make mrproper		#净化
sudo cp /boot/config-`uname -r`  ./.config 
sudo make menuconfig
load→(.config)OK→SAVE→(.config)OK→EXIT
	          #对内核选项进行配置选择
sudo gedit .config

与密钥有关,老师告诉我们的,暂时解释不清楚为什么要这样改

sudo make bzImage -jN(一般N=8就可以)
sudo make modules -jN
sudo make INSTALL_MOD_STRIP=1 modules_install
sudo mkinitramfs /lib/modules/6.8.6 -o /boot/initrd.img-6.8.6-generic
sudo cp /usr/src/linux-6.8.6/arch/x86/boot/bzImage    /boot/vmlinuz-6.8.6-generic
sudo cp  /usr/src/linux-6.8.6/System.map    /boot/System.map-6.8.6
make install
update-grub2

7.重启进入6.8.6,在主目录编写一个测试文件

sudo gedit test1.c

在这里插入图片描述这个测试程序的路径不固定,自己找的到就行,syscall函数传入的是系统调用号

sudo gcc test1.c -o test
sudo ./test
sudo dmesg #显示日志缓冲区内容

8.能够在打印信息中找到自己想打印的内容,说明就成功了
在这里插入图片描述

如何向Linux内核中增加设备驱动

目的:以插模块的方式向Linux内核增加一个字符设备驱动
呈现效果:向内核插入一个模块,编写测试文件,使运行该文件时可以从键盘输入字符。
可参考资料
如何编写一个简单的Linux内核模块
Q:字符设备驱动是什么?
A:字符设备是 Linux 驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的。比如我们最常见的点灯、按键、 IIC、 SPI,LCD 等等都是字符设备,这些设备的驱动就叫做字符设备驱动。
1.编写Makefile文件
注:代码是老师提供的,独立编写一个模块难度太大我选择先放弃

ifeq ($(KERNELRELEASE),)
//检查KERNELRELEASE变量是否未设置。KERNELRELEASE是内核构建系统设置的一个变量,用于标识内核的版本号

KERNELDIR := /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)
//当前工作目录(即,模块源代码目录)的绝对路径

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
	//用于安装模块到内核的模块目录中

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean

else
    obj-m := test_drv.o
endif

2.编写test.c文件和test_drv.c文件

/* test.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define 	TEST_DEVICE_FILENAME		"/dev/test_dev"
#define		BUFF_SZ				1024


int main()
{
	int fd, nwrite, nread;
	char buff[BUFF_SZ];

	fd = open(TEST_DEVICE_FILENAME, O_RDWR);
	if (fd < 0)
	{
		perror("open");
		exit(1);
	}
		
	do
	{
		printf("Input some words to kernel(enter 'quit' to exit):");
		memset(buff, 0, BUFF_SZ);
		if (fgets(buff, BUFF_SZ, stdin) == NULL)
		{
			perror("fgets");
			break;
		}
		buff[strlen(buff) - 1] = '\0';
		
		if (write(fd, buff, strlen(buff)) < 0)
		{
			perror("write");
			break;
		}
		
		if (read(fd, buff, BUFF_SZ) < 0)
		{
			perror("read");
			break;
		}
		else
		{
			printf("The read string is from kernel:%s\n", buff);
		}
		
	} while(strncmp(buff, "quit", 4));
	
	close(fd);
	exit(0);
}
/* test_drv.c */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#define 	TEST_DEVICE_NAME	"test_dev"
#define		BUFF_SZ			1024

MODULE_LICENSE("GPL");

/*全局变量*/
static struct cdev test_dev;
unsigned int major =0;
static char *data = NULL;

/*函数声明*/
static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos);
static ssize_t test_write(struct file *file,const char *buffer, size_t count,loff_t *f_pos);
static int test_open(struct inode *inode, struct file *file);
static int test_release(struct inode *inode,struct file *file);

/*读函数*/
static ssize_t test_read(struct file *file, char *buf, size_t count, loff_t *f_pos)
{
	int len;
	if (count < 0 )
	{
		return -EINVAL;
	}
	len = strlen(data);
	count = (len > count)?count:len;
	if (raw_copy_to_user(buf, data, count))
	{
		return -EFAULT;
	}
	return count;
}

/*写函数*/
static ssize_t test_write(struct file *file, const char *buffer, size_t count, loff_t *f_pos)
{
	if(count < 0)
	{
		return -EINVAL;
	}
	memset(data, 0, BUFF_SZ);
	count = (BUFF_SZ > count)?count:BUFF_SZ;
	if (raw_copy_from_user(data, buffer, count))
	{
		return -EFAULT;
	}
	return count;
}

/*打开函数*/
static int test_open(struct inode *inode, struct file *file)
{
	printk("This is open operation\n");
	data = (char*)kmalloc(sizeof(char) * BUFF_SZ, GFP_KERNEL);
	if (!data)
	{
		return -ENOMEM;
	}
	memset(data, 0, BUFF_SZ);
	return 0;
}

/*关闭函数*/ 
static int test_release(struct inode *inode,struct file *file)
{
	printk("This is release operation\n");
	if (data)
	{
		kfree(data);
		data = NULL;
	}
	return 0;
}

static void test_setup_cdev(struct cdev *dev, int minor,
		struct file_operations *fops)
{
	int err, devno = MKDEV(major, minor);
    
	cdev_init(dev, fops);
	dev->owner = THIS_MODULE;
	dev->ops = fops;
	err = cdev_add (dev, devno, 1);
	if (err)
	{
		printk (KERN_NOTICE "Error %d adding test %d", err, minor);
	}
}

/* tests设备的file_operations结构 */
static struct file_operations test_fops = 
{
	.owner	 = THIS_MODULE,
	.read	 = test_read,
	.write	 = test_write,
	.open	 = test_open,
	.release = test_release,
};

/*模块注册入口*/
int init_module(void)
{
	int result;
	dev_t dev = MKDEV(major, 0);

	if (major)
	{
		result = register_chrdev_region(dev, 1, TEST_DEVICE_NAME);
	}
	else 
	{
		result = alloc_chrdev_region(&dev, 0, 1, TEST_DEVICE_NAME);
		major = MAJOR(dev);
	}

	if (result < 0) 
	{
		printk(KERN_WARNING "Test device: unable to get major %d\n", major);
		return result;
	}

	test_setup_cdev(&test_dev, 0, &test_fops);
	printk("The major of the test device is %d\n", major);
	return 0;
}

/*卸载模块*/
void cleanup_module(void) 
{
	cdev_del(&test_dev);
	unregister_chrdev_region(MKDEV(major, 0), 1);
	printk("Test device uninstalled\n");
}
/*test_drv_load*/
#!/bin/sh
module="test_drv"
device="test_dev"
mode="664"
group=""//定义设备文件的组


# remove stale nodes
rm -f /dev/${device} 

# invoke insmod with all arguments we got
# and use a pathname, as newer modutils don't look in . by default
/sbin/insmod ./$module.ko $* || exit 1

major=`cat /proc/devices | awk "\\$2==\"$device\" {print \\$1}"`

mknod /dev/${device} c $major 0

# give appropriate group/permissions
chgrp $group /dev/${device}
chmod $mode  /dev/${device}
/*test_drv_unload*/
#!/bin/sh
module="test_drv"
device="test_dev"

# invoke rmmod with all arguments we got
/sbin/rmmod $module $* || exit 1

# remove nodes
rm -f /dev/${device}

exit 0

2.进入有Makefile文件的目录

make
sudo gcc test.c -o test
sudo ./test_drv_load
sudo ./test
sudo ./test_drv_unload
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值