Linux学习
Linux命令学习
注意点
- Linux中区分大小写
- Linux中正斜杠
/
表示目录
Linux的终端窗口
$
表示Shell提示符(普通用户)
作用:用户可以在提示符后输入带有选项和参数的字符命令,并能够在终端窗口中看到命令的运行结果,此后,将会出现一个新的提示符,标志着新命令行的开始#
表示Shell提示符(超级管理员)
作用:权限更高,可以执行更多操作Tab键
可以自动匹配并补全命令
作用:按Tab键时,如果系统只找到一个和输入字符相匹配的目录或文件,则自动补齐;如果没有匹配的内容或有多个相匹配的名字,系统将发出警鸣声,再按一下Tab键将列出所有相匹配的内容,以供用户选择上下键
可以翻阅浏览历史&
可以使命令在后台执行,执行的命令后跟上一个“&”符号即可
find / -name httpd.conf &
;
可以让多条命令在同一行执行
cd /;ls
文件目录类命令
- 浏览目录
pwd
:用于显示用户当前所在的目录。如果用户不知道自己当前所处的目录,就可以使用这个命令获得当前所在目录。cd
:切换目录
cd //切换至用户登录时的工作目录,一般Linux用终端打开时是该目录下
cd dir1 // 切换至当前目录下的dir1子目录下
cd ~ //切换至用户登录时的工作目录(用户的家目录)
cd .. //切换至当前目录的父目录(也就是上一级目录)
cd ../user //切换至当前目录的父目录的user子目录(也就是切换上一级目录后再去user子目录)
cd /dir1/subdir1 //利用绝对路径表示改变到/dir1/subdir1目录下
- 浏览文件
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行开始显示指定文件的内容。
- 目录操作
mkdir
:创建目录rmdir
:删除目录
- 文件操作
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,但检查的是文件内容被修改的时间。
下载软件的三种形式
- apt命令
- dpkg(.deb)
- 软件源(/etc/apt/sources.list)
如何在linux上安装和配置Apache服务器
安装
- 在桌面创建一个文件夹,例如我创建的是ccweb.com,右键通过终端打开
- 更新系统存储库:
sudo apt update
- 使用apt命令安装Apache:
sudo apt install apache2
- 检查安装:
apache2 -version
配置UFW防火墙
- 列出UFW应用程序配置文件:
udo ufw app list
- 在UFW上允许Apache并验证其状态:
sudo ufw allow 'Apache'
更新防火墙规则
sudo ufw status
展示防火墙状态
如何在Ubuntu上安装和配置Apache2 web服务器
教程(要用电脑打开):如何在Ubuntu18.04上安装和配置Apache2 web服务器
笔者注:我用这个教程在Ubuntu22.04上安装和配置也可以成功,但是由于个人原因遇到了一些问题
- 输入域名的时候字母打错了,导致配置文件内的信息不正确。
解决:再改一遍配置文件,并把不正确的域名可以反推通过下面的命令进行禁用,后面的配置文件可以更换为自己的
sudo a2dissite xxx.com.conf
- 需要做ip地址和域名的映射(如果您已购买域名则不用)
hostname -I
//查看本机地址
sudo nano /etc/hosts
//通过nano编辑器打开配置文件
//在文件末尾添加
本机地址 域名
注意:
- 域名是http或https后面的部分,例如我设置的网页是
http://www.xx.com
,那么我此处配置的域名就是www.xx.com
- ip地址会随时变化,有时登录不进去可以查看ip地址是否变化,然后改一下映射
如何在Ubuntu上安装Hadoop
教程:Hadoop安装教程_单机/伪分布式配置_Hadoop2.6.0(2.7.1)/Ubuntu14.04(16.04)
遇到的一些问题:
- 创建hadoop用户之后要重启,登录到hadoop用户里面完成接下来的操作(命令行切换用户应该也可以,但我没试过)
- 安装java环境时要将添加的环境变量放在文件开始位置,可能是避免依赖问题或者防止覆盖
- 官网安装hadoop3太慢,在清华镜像网站下载:hadoop-3.4.0.tar.gz
- 通过
jbs
命令查看进程全部启动但是网站打不开:
- 首先查看防火墙的设置,尝试关闭防火墙
- 换一个端口,hadoop端口变化(50700-9870),hadoop3是9870端口可以进,hadoop2是50700
如何使用vim编辑器
esc键
进入命令模式
shift + O
:进入编辑模式shift + :+ wq
:保存并退出
Apache简单配置SSL的方法(Ubuntu20.04+HTTPS)
教程:Apache简单配置SSL的方法(Ubuntu20.04+HTTPS)
遇到了以下问题:
-
打开的conf文件是空白的,原因是原教程的复制的路径的最后的文件少了个.conf的后缀,导致打开的文件和复制的文件不对应
-
证书中的信息注解中的主机名要通过
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