Linux Grub引导界面美化

最近一直在整理Debian+Windows双系统的问题,个人觉得grub启动菜单不是特别养眼,所以搜索了一下,试用了rEFind。但是个人觉得rEFind,grub,Windows三重引导让人很不舒服,所以还是对grub主题进行了一下修改。

下面是修改过程

一. 挑选喜欢的主题并下载

进到GNOME-LOOKING.org

然后选择GRUB Themes,选一个自己最喜欢的下载即可,我选的是评分第一的这个,vimix,确实看着很养眼,简约舒服

点进去下载自己的版本即可

我下了一个,顺带放在这里,有兴趣的话可以点击自取

注意我把3种格式打包了一下,所以要解压两次,选择适合自己的版本


二.安装主题

主题下载之后,根据自己的情况去找到该文件

  1. 解压主题

首先需要对该文件进行解压。

tar -Jxf Vimix-1080p.tar.xz

解压之后可以看到文件夹Vimix-1080P,里面有一个安装脚本,名为install.sh,大家可以直接使用脚本安装

bash install.sh

参考文章:https://zhuanlan.zhihu.com/p/94331255

解决Linux下挂载的NTFS分区(Windows分区)只读问题。

解决方案

关闭Windows下的快速启动,我用的机器是Windows11+Debian11

方法:

win+r呼出运行框,输入control打开控制面板

然后选择硬件和声音->电源设置->选择电源按钮的功能。打开如上图对话框。

将“关机设置”下面的“启用快速启动(推荐)”前的勾取消掉(单击复选框),如上图红框所示。然后点击下方“保存修改”按钮。如果复选框是灰色不可用状态,单击上方的“更改当前不可用的设置”(上图红线所示)即可。

我的是英文版,仅供参考

参考文章:https://zhuanlan.zhihu.com/p/161505413

Linux内存回收之drop cache

Linux有自己完备的一套内存回收机制,并不需要人为的干预,但它同时也提供了一种手动释放的手段,可以让我们在调试的时候使用,方法是通过设置”/proc/sys/vm/drop_cache”参数。

这个参数可接收3个数字的输入,分别是1, 2和3,写入1代表只释放page cache的可回收部分,写入2代表只释放slab cache中的可回收部分。可回收的slab cache是指在调用”kmem_cache_create”函数向slab分配器申请内存时,使用了”SLAB_RECLAIM_ACCOUNT”标志位,主要就是dentry cache和inode cache。

写入3代表同时释放page cache和reclaimable slab cache。很好记,1+2=3嘛,事实上,1就是二级制的01,2就是二进制的10,运行drop cache就是靠这两个置1的bit判断的。具体的实现函数是”drop_caches_sysctl_handler”(代码位于/fs/drop_caches.c):

int drop_caches_sysctl_handler(...)
{
    if (sysctl_drop_caches & 1) {
	iterate_supers(drop_pagecache_sb, NULL);
	count_vm_event(DROP_PAGECACHE);
    }
    if (sysctl_drop_caches & 2) {
        drop_slab();
	count_vm_event(DROP_SLAB);
    }
    ...
}

写入后只会执行一次,后续不用再去管它,不需要写入0去清除什么的(其实你写入0也是不会成功的),如果非强迫症犯了想把它清掉,那就写入4好了,4是”100″,末尾两位是0就行。

【page cache的释放

在执行”echo 1 > /proc/sys/vm/drop_caches”命令之前和之后,分别查看”meminfo”中page cache的数量:

可见,page cache所占用的内存明显减少,但并没有完全清空。因为这种方式只能清空page cache中”clean“的部分,也就是已经和外部磁盘同步过的部分。

因为”clean”的部分回收起来最简单,既然已经同步过了,直接丢弃即可,下次要用再从磁盘上拷贝回来就可以了,而”dirty”的部分需要先writeback到磁盘,才能释放。所以,”drop cache”准确地应该叫drop clean cache(如果想释放”dirty”的page cache,可以先使用”sync”命令强制同步一下)。

具体实现

以下是向”drop_cache”写入1后的函数调用过程:

与实现自动回收的kswapd线程通过扫描LRU链表不同,手动回收page cache是遍历各个文件系统的各个文件,来寻找可供回收的clean pages。

【slab cache的释放

page cache对应的是文件系统中的文件数据(userdata),而inode cache对应的是文件系统中文件的控制结构(metadata)。对于磁盘文件系统,内存inode存在后备存储,因此同page cache一样,较易在内存中重建,释放的代价较低。dentry虽然在磁盘上没有直接对应的结构,但也可根据文件系统中目录inode的信息进行重建。

还是和之前page cache的实验一样,在执行”echo 2 > /proc/sys/vm/drop_caches”命令之前和之后,分别查看”meminfo”中slab cache的大小。

代表slab cache中可回收部分的”SReclaimable”明显减少,而代表不可回收部分的”SUnreclaim”的值基本没有变化。

再来看下回收前后dentry cache的数量变化,可见,处于”unused“状态的dcache都被回收了,共49721个:

而inode cache的数量,减少了44407个:

一个内存inode被一个或多个dentry指向,如果指向一个inode的dentry都被释放,那么该inode也就没有继续存在于内存的意义,也会被同步释放,且由于这种指向关系,释放的inode object总数应略小于释放的dentry object的总数。

借助crash工具的”struct”命令,可以快速得知一个结构体的大小,以笔者使用的”4.18.0-80.el8.x86_64″内核版本为例,dentry和inode的结构体大小分别是208字节和648字节,计算一下,差不多就等于”SReclaimable”中减少的部分。

具体实现

上述操作对应的函数调用过程大致是这样的:

从dcache和icache的LRU链表获取可回收的数量后,还可以通过”/proc/sys/vm/vfs_cache_pressure“参数来调节slab cache的「回收倾向」。

shrinker -> count_objects (super_cache_count)
total_objects += list_lru_shrink_count(&sb->s_dentry_lru, sc);
total_objects += list_lru_shrink_count(&sb->s_inode_lru, sc);
total_objects = vfs_pressure_ratio(total_objects); // 按百分比调整

该参数的值越小,则回收slab cache的比例也就越低,当值为0时,即使内存资源紧张也不回收slab cache(非常类似于调节anonymous page和page cache回收比例的“swappiness”参数)。笔者的系统采用的是默认值100,所以是全部回收。

如果不是全部回收,那么在确定了回收的slab object总数后,需根据dcache和icache各自所占的比例进行分摊(”sc->nr_to_scan“是通过上一个函数返回的”total_objects”经过进一步的调整获得):

shrinker -> scan_objects (super_cache_scan)
dentries = mult_frac(sc->nr_to_scan, dentries, total_objects);
inodes = mult_frac(sc->nr_to_scan, inodes, total_objects);

获得”sc->nr_scanned“的扫描结果之后,就是对dcache和icache实际的清除操作了(由于dentry和inode的指向关系,应先释放dcache),可通过perf工具查看此过程的时间百分比,笔者的一次实验结果如下:

69.43%  prune_dcache_sb
27.41%  prune_icache_sb

【小结

清除page cache和slab cache可以快速释放内存,cache虽然占据了内存空间,但其本来就是为了提高性能而存在的,在手动清除后的一段时间里,系统的整体运行效率将受到影响。如果发现即便负责自动回收的kswapd频繁启动,系统的内存资源依然吃紧,应尝试去寻找部分内存始终不能有效释放的原因,手动清除并不能解决根本问题。

笔者在工作中就曾经遇到过这样的案例:kswapd由于持续运行,导致占据了大量的CPU资源,后来发现root cause是有进程一直再往tmpfs里面打印log,而tmpfs属于shmem,在性质上是anonymous pages,内存回收时应该被swap out到外部的swap space。

但系统没有在外部flash设置swap分区,手动drop cache只能回收page cache和slab cache,对anony page是没有用的。tmpfs里的内容不断增加,导致空闲内存低于low watermark,触发kswapd,但没有swap分区,kswapd怎么使劲也是无能为力的,最终的结果就是内存占用率和CPU占用率都很高,系统可能就挂掉了。

参考内存清理脚本(可根据自己的需求进行调整)

#!/bin/bashecho “开始清除缓存”

sync;sync;sync #写入硬盘,防止数据丢失

sleep 10 #延迟10秒

echo 1 > /proc/sys/vm/drop_caches

echo 2 > /proc/sys/vm/drop_caches

echo 3 > /proc/sys/vm/drop_caches

echo “清理结束”

参考文章:https://zhuanlan.zhihu.com/p/93962657

ORA-03113: end-of-file on communication channel解决步骤

通常这个异常都是空间满导致,查询alter_orcl.log 这个文件一般都能看到错误信息,其中orcl为数据库的sid。
一般都会有类似的日志:
ORA-19815: WARNING: db_recovery_file_dest_size of 5218762752 bytes is 100.00% used, and has 0 remaining bytes available.


You have following choices to free up space from recovery area:

  1. Consider changing RMAN RETENTION POLICY. If you are using Data Guard,
    then consider changing RMAN ARCHIVELOG DELETION POLICY.
  2. Back up files to tertiary device such as tape using RMAN
    BACKUP RECOVERY AREA command.
  3. Add disk space and increase db_recovery_file_dest_size parameter to
    reflect the new space.
  4. Delete unnecessary files using RMAN DELETE command. If an operating
    system command was used to delete files, then use RMAN CROSSCHECK and
    DELETE EXPIRED commands.

解决方案一、清理文件(如果不想清理文件可以查看解决方案二)

切换到oracle用户执行:

su – oracle

[oracle@db~]$ sqlplus /nolog

SQL*Plus: Release 11.2.0.1.0 Production on Thu Jun 23 17:44:00 2016

Copyright (c) 1982, 2009, Oracle. All rights reserved.
sql> conn / as sysdba

Connected to an idle instance.

sql> startup nomount

ORACLE instance started.
再执行
sql> alter database mount;

Database altered.

接下来就要清理空间了
另外起一个终端,找到文件存放路径:
[oracle@db~]$ cd /data2/oracle/flash_recovery_area/ORCL/archivelog/
[oracle@db archivelog]$ pwd
/data2/oracle/flash_recovery_area/ORCL/archivelog
[oracle@db archivelog]$ ls
2016_06_01 2016_06_02 2016_06_03 2016_06_04 2016_06_05 2016_06_06 2016_06_07 2016_06_08 2016_06_21 2016_06_22 2016_06_23
[oracle@db archivelog]$ rm -rf 2016_05*
删除掉不要的文件。

接下来需要启动rman了
[oracle@db archivelog]$ rman target /

Recovery Manager: Release 11.2.0.1.0 – Production on Thu Jun 23 17:49:55 2016

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.

connected to target database: ORCL (DBID=1412518558)

RMAN> crosscheck archivelog all;

一堆的提示不管它,再执行:
RMAN> delete expired archivelog all;
删除掉过期的归档文件。

接下来回到刚才的sqlplus终端,执行如下:
SQL> alter database open;

Database altered.

SQL>

好了,数据库起来了。
然后启动监听端口就万事大吉了。

解决方案二、增加数据库空间

如果磁盘空间没有满,想增加闪回恢复区。
在mount数据库后,执行:
alter system set db_recovery_file_dest_size=8G;
修改的过程如下:
<pre>
[oracle@db~]$ sqlplus /nolog

SQL*Plus: Release 11.2.0.1.0 Production on Fri Jun 24 10:56:40 2016

Copyright (c) 1982, 2009, Oracle. All rights reserved.

SQL> conn /as sydba
SP2-0306: Invalid option.
Usage: CONN[ECT] [{logon|/|proxy} [AS {SYSDBA|SYSOPER|SYSASM}] [edition=value]]
where <logon> ::= <username>[/<password>][@<connect_identifier>]
<proxy> ::= <proxyuser>[<username>][/<password>][@<connect_identifier>]
SQL> exit
[oracle@firebox42 ~]$ sqlplus /nolog

SQL*Plus: Release 11.2.0.1.0 Production on Fri Jun 24 10:57:02 2016

Copyright (c) 1982, 2009, Oracle. All rights reserved.

SQL> conn /as sysdba
Connected to an idle instance.
SQL> startup nomount
ORA-01012: not logged on
SQL> shutdown abort
ORACLE instance shut down.
SQL> startup nomount
ORACLE instance started.

Total System Global Area 1.0689E+10 bytes
Fixed Size 2216344 bytes
Variable Size 6845107816 bytes
Database Buffers 3825205248 bytes
Redo Buffers 16945152 bytes
SQL> alter database mount;

Database altered.

SQL> show parameter db_recover;

NAME TYPE VALUE


db_recovery_file_dest string /opt/oracle/flash_recovery_are
a
db_recovery_file_dest_size big integer 3882M
SQL> alter system set db_recovery_file_dest_size=80G;

System altered.

SQL> alter database open;

Database altered.

参考文章:https://www.jianshu.com/p/97b86d95894b

将VMware转换为VirtualBox(或将VirtualBox转换为VMware)

虚拟机本质上仅仅是这-您可以尝试所有新的操作系统,程序或任何您需要的辅助空间。它基本上就像单独的计算机一样工作,您可以安装所需的任何OS,并在其中安装程序。这一切都不会影响您当前的设置,因此,如果出现问题,则不会影响您的主操作系统。基本上,您是在主操作系统上的软件中运行辅助操作系统。

这样做有很多选择,两个最受欢迎的软件是VMwareVirtual Box。两者的工作方式相似。他们创建了一个容器,您可以在其中运行和安装操作系统,就像将其安装在单独的PC上一样。这些使您可以选择要分配给辅助OS的RAM,存储量和处理能力。唯一的是,如果要从使用其中一种迁移到另一种,那么任务就不那么简单了。如果要在从VMware迁移到Virtual Box时保持操作系统设置及其所有文件,程序和设置完整,请执行以下步骤。

将VMware转换为Virtual Box,反之亦然

进行转换之前首先要安装一个VMware Player(点击可进入官方下载页面)

从VMware到Virtual Box

在开始之前,请确保要导出的虚拟机处于“关闭电源”状态,否则不要处于其他状态。为了能够在Virtual Box中运行它,我们需要将VMware文件(.vmx)转换为Virtual Box文件(.ovf)。为此,请按照以下步骤操作。尽管没有基于GUI的方法,但这也不是那么困难。

现在关闭电源,让我们开始。

  1. 打开VMware安装目录。默认情况下,它是  C:\ Program Files(x86)\ VMware \ VMware Player。
  2. 现在,在文件夹内,按住shift键右键单击  文件夹中存在的OVF工具
  1. 选择“在  此处打开命令窗口” 选项。
  2. 现在,将打开一个CMD窗口。
  3. 现在,以以下格式运行命令以将vmx文件转换为ovf。
    ovftool“源文件.vmx” export.ovf
  1. 此处,源文件部分将替换为源vmx文件的位置。
  2. 保持扩展名和导出部分相同。
  3. 例如,如果文件存储在相应目录中,则  ovftool“ D:\ Documents \ Virtual Machines \ Windows 7 \ Windows 7.vmx” D:\ Documents \ export.ovf是我正在运行的命令。
  1. 现在,该命令将运行,文件将被导出到相应目录中。

导出现已完成。现在,您也可以在Virtual Box上打开具有相同文件,操作系统和设置的相同虚拟机。要在Virtual Box中打开导出的文件,请按照以下步骤操作。

  1. 打开虚拟盒子。
  2. 单击文件选项,然后选择导入设备… 选项。
  1. 现在浏览并选择新导出的.ovf文件。
  2. 现在单击下一步。
  1. 最后,单击导入 按钮以完成导入.ovf文件。

完成后,您也应该能够在Virtual Box上使用相同的虚拟机。

虚拟机到VMware

虽然没有基于GUI的简单方法将VMware转换为Virtual Box。但是,将Virtual Box转换为VMware相对简单得多。它提供了一个基于GUI的简洁程序,因此您不必费心CMD命令和错误。要进行其他转换,请按照以下步骤操作。使用这个

  1. 打开虚拟盒子。
  2. 单击文件 按钮,然后单击  导出设备… 选项。
  1. 在“  导出虚拟设备” 向导中,选择要导出的虚拟机,然后单击“ 下一步”。
  1. 现在,选择要存储导出文件的位置,然后单击“ 下一步”。
  1. 在“  设备设置” 页面中,单击“  导出” 以完成导出过程。

现在,导出的文件已准备好在VMware上运行。为此,请按照以下步骤操作。值得注意的是,您将在导入过程中收到警告,但这绝对可以。只需单击“  重试” 按钮,这一次应该将其导入,没有任何问题或错误。

  1. 打开VMware。
  2. 单击“  打开虚拟机” 选项以打开新创建的虚拟机。
  1. 浏览并打开文件。
  2. 现在,只需单击导入 按钮。
  1. 现在,该过程完成后,您可能会看到一条错误消息。
  1. 单击“  重试” 按钮以重试该操作,它将在这次导入且没有任何错误。
  2. 如果错误没有消失,则可能必须重新尝试导出过程。
  3. 完成后,您应该在VMware Player中看到新的虚拟机。

现在,您可以轻松地将虚拟机从VMware转换为Virtual Box,也可以采用其他方法。该过程非常简单,并且工作得很好,因为这两个程序都能够将虚拟机导出为相应的格式。

但是,如果遇到任何错误,请再次尝试导入过程,如果未解决,请尝试再次将其全部导出。

迁移之后个人遇到了虚拟机版本识别错误,install VMware tools 为灰色无法安装的问题,解决方案可以参考这篇文章

参考文章:https://blog.csdn.net/zb774095236/article/details/103046675

VirtualBox网络配置方案

VirtualBox是开源的虚拟机软件,这里重点讲一下它的的网络配置。

一般虚拟机都会提供了三种网络工作模式,分别是:

  • Bridged(桥接模式
  • NAT(网络地址转换模式)
  • Host-Only(仅主机模式)

这三种网络模式有什么区别,会在哪种情况下使用?我们来详细分析一下。


1. Bridged(桥接模式)

桥接模式就是将主机的网卡,与虚拟机虚拟的网卡利用虚拟网桥进行通信。

  • 类似于把物理主机虚拟为一个交换机,所有桥接设置的虚拟机连接到这个交换机的一个接口上,物理主机也同样插在这个交换机当中,所以所有桥接下的网卡与网卡都是交换模式的,相互可以访问而不干扰。
  • 虚拟机ip地址需要与主机在同一个网段,如果需要联网,则网关与DNS需要与主机网卡一致。

其网络结构如下图所示:

VirtualBox虚拟机会默认安装Bridged网卡和Host-Only网卡:

在虚拟机里选择要桥接的物理网卡,这里选择的是Intel wi-fi这个物理网卡:

因为启用了【网卡1】,虚拟机会给Ubuntu系统配置一块虚拟网卡【enp03】,这里我们设置Ubuntu虚拟网卡和桥接的Windows物理网卡在同一个网段,这样就可以实现互通了;

因为windows的wifi网卡地址是:10.4.23.200,所以设置虚拟机的enp0s3网卡地址为:10.4.23.218;这样两个系统现在都在真实的网络上,且可以正常上网。

小结:

  • 桥接模式:物理机和虚拟机在网络上是一样的,虚拟系统相当于在此网络下的一个独立系统,需要分配网络的一个独立IP。
  • 连接时指定的桥接到哪个物理网卡,相当于要把虚拟系统接到那个网段的交换机上。

2. NAT(地址转换模式)

NAT模式下,虚拟机访问网络的所有数据都是由主机提供的,虚拟机并不真实的存在于网络上,主机和网络中的任何机器是不能查看和访问这个虚拟机的。

其网络结构如下图所示:

NAT模式借助虚拟NAT设备和虚拟DHCP服务器,使得虚拟机可以联网。

  • DHCP用于动态分配虚拟机的IP地址。
  • 物理机下的虚拟网卡,在VMware下是VMnet8网卡,在VirtualBox下不可见。

另外,在连接上:

  • 虚拟机可以通过网络访问主机
  • 主机无法通过网络访问虚拟机,如:telnet 是连不到虚拟机中的。

小结:

这种虚拟系统都是隐藏在物理机后面的机器,在网络上是看不见的,地址由DHCP负责分配,上网有NAT设备负责。

这这网络连接实现有些系统不需要暴露在网络节点上又需要上网的这种需求,这也是最简单的一种虚拟机使用方式。

3. Host-Only(仅主机模式)

Host-Only听名字就是只和主机建立关系。这种模式是将虚拟机与外网隔开,使得虚拟机成为一个独立的系统,只与主机相互通讯。

它的网络结构是在NAT网络的基础上,去除虚拟NAT设备让它不能上网,如下图所示:

在虚拟机安装完后,windows下就会多出来一个Host-Only网卡,这个虚拟网卡就是用来实现通信用的。

在选择Host-Only模式时,需要选择一块Host-Only网卡用于和虚拟机进行通信使用:

同时设置虚拟机的IP地址和Host-Only的网卡地址要在同一个网段:

相互ping都是通的,这也实现了物理机和虚拟机互通的功能。


三种模式总结:

  • 桥接模式:实现虚拟机在真实的网络上;
  • NAT模式:实现虚拟机隐藏在物理机之后,能上网,但不能访问物理机;
  • Host-Only模式:实现虚拟机隐藏在物理机之后,不能上网,但可以访问物理机;

上面只是介绍选用一个网络模式的情况,在实际使用中,我们还可以同时使用两种及以上的网络模式,比如:NAT + Host-Only,这样可以实现虚拟机上网和物理机通信两种能力。

以上就是VirtualBox最常用的网络配置,希望对你有用。

参考文章:https://zhuanlan.zhihu.com/p/403513377

一下为个人配置,可能与上面的ip分配模式不完全相同,仅供参考

如果想要用只配置nat网络,并且让主机访问到虚拟机的话就需要配置端口转发,

配置位置:管理->全局设定->网络->主机使用的NAT网络,我这边配置的是NatNetwork,双击即可看到端口转发按钮

点击即可看到端口转发规则界面,我这边配置的nat网关ip是192.168.77.1,子系统ip是192.168.77.4

通过如下配置,主机即可通过访问192.168.77.1:12580来实现对于192.168.77.4:22的访问

linux下的C语言开发

看到一个很好的文章,学习记录一下,原文链接可以在最后找到


在很多人的眼里,C语言和linux常常是分不开的。这其中的原因很多,其中最重要的一部分我认为是linux本身就是C语言的杰出作品。当然,linux操作系统本身对C语言的支持也是相当到位的。作为一个真正的程序员来说,如果没有在linux下面用C语言编写过完整的程序,那么只能说他对C语言本身的理解还相关肤浅,对系统本身的认识也不够到位。作为程序员来说,linux系统为我们提供了很多理想的环境,这其中包括了下面几个方面,

(1)完善的编译环境,包括gcc、as、ld等编译、链接工具
(2)强大的调试环境,主要是gdb工具
(3)丰富的自动编译工具,主要是make工具
(4)多样化的os选择,ubuntu、redflag等等
(5)浩瀚的开源代码库

当然,不管我怎么说,最终朋友们还是应该自己勇敢地跨出前进的第一步。
如果还没有过Linux编程经验的朋友可以首先在自己的pc上面安装一个虚拟机,然后就可以在shell下面编写自己的C语言代码了。

#include &lt;stdio.h>
int main()
{
    printf("hello!\n");
    return 1;
}

编写完上面的代码后,你需要做的就是两个步骤:
1、输入 gcc hello.c -o hello;
2、输入./hello。
如果一切正常的话,此时你应该会在屏幕上看到一行hello的打印。如果你看到了,那么恭喜你,你已经可以开始linux的c语言编程之旅了。

当然,我们不会满足于这么简单的打印功能。下面就可以编写一个简单的迭代函数,

#include &lt;stdio.h>
int iterate(int value)
{
    if(1 == value)
        return 1;
    return iterate(value - 1) + value;
}
int main()
{
    printf("%d\n", iterate(10));
    return 1;
}

此时,同样我们需要重复上面的步骤:
1、输入gcc hello.c -o hello;
2、输入./hello。
当然此时如果一切OK的话,你就会看到屏幕会有55这个数的输出。本来1到10的数据之和就是55, 这说明我们的程序是正确的。

当然, 还会有一些朋友对程序的反汇编感兴趣,那么他需要两个步骤:
1、gcc hello.c -g -o hello;
2、objdump -S -d ./hello。
之所以在gcc编译的时候加上-g是为了添加调试信息,objdump中的-S选项是为了在显示汇编代码的时候同时显示原来的C语言源代码。

int iterate(int value)
{
    8048374: 55 push %ebp
    8048375: 89 e5 mov %esp,%ebp
    8048377: 83 ec 08 sub $0x8,%esp
    if(1 == value)
        804837a: 83 7d 08 01 cmpl $0x1,0x8(%ebp)
        804837e: 75 09 jne 8048389 &lt;iterate+0x15>
        return 1;
    8048380: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp)
    8048387: eb 16 jmp 804839f &lt;iterate+0x2b>
    return iterate(value -1) + value;
    8048389: 8b 45 08 mov 0x8(%ebp),%eax
    804838c: 83 e8 01 sub $0x1,%eax
    804838f: 89 04 24 mov %eax,(%esp)
    8048392: e8 dd ff ff ff call 8048374 &lt;iterate>
    8048397: 8b 55 08 mov 0x8(%ebp),%edx
    804839a: 01 c2 add %eax,%edx
    804839c: 89 55 fc mov %edx,0xfffffffc(%ebp)
    804839f: 8b 45 fc mov 0xfffffffc(%ebp),%eax
}
80483a2: c9 leave
80483a3: c3 ret

linux下的C语言开发(makefile编写)
对于程序设计员来说,makefile是我们绕不过去的一个坎。可能对于习惯Visual C++的用户来说,是否会编写makefile无所谓。毕竟工具本身已经帮我们做好了全部的编译流程。但是在Linux上面,一切变得不一样了,没有人会为你做这一切。编代码要靠你,测试要靠你,最后自动化编译设计也要靠你自己。想想看,如果你下载了一个开源软件,却因为自动化编译失败,那将会在很大程度上打击你学习代码的自信心了。所以,我的理解是这样的。我们要学会编写makefile,至少会编写最简单的makefile。

首先编写add.c文件,

#include "test.h"
#include &lt;stdio.h>
int add(int a, int b)
{
    return a + b;
}
int main()
{
    printf(" 2 + 3 = %d\n", add(2, 3));
    printf(" 2 - 3 = %d\n", sub(2, 3));
    return 1;
}

再编写sub.c文件,

#include "test.h"
int sub(int a, int b)
{
    return a - b;
}

最后编写test.h文件,

#ifndef _TEST_H
#define _TEST_H
int add(int a, int b);
int sub(int a, int b);
#endif

那么,就是这三个简单的文件,应该怎么编写makefile呢?

test:
add.o sub.o
gcc -o test add.o sub.o
add.o:
add.c test.h
gcc -c add.c
sub.o:
sub.c test.h
gcc -c sub.c
clean:
rm -rf test
rm -rf *.o

linux下的C语言开发(gdb调试)
编写代码过程中少不了调试。在windows下面,我们有visual studio工具。在linux下面呢,实际上除了gdb工具之外,你没有别的选择。那么,怎么用gdb进行调试呢?我们可以一步一步来试试看。

#include &lt;stdio.h>
int iterate(int value)
{undefined
    if(1 == value)
        return 1;
    return iterate(value - 1) + value;
}
int main()
{undefined
    printf("%d\n", iterate(10));
    return 1;
}

既然需要调试,那么生成的可执行文件就需要包含调试的信息,这里应该怎么做呢?很简单,输入 gcc test.c -g -o test。输入命令之后,如果没有编译和链接方面的错误,你就可以看到 可执行文件test了。

调试的步骤基本如下所示,
(01) 首先,输入gdb test
(02) 进入到gdb的调试界面之后,输入list,即可看到test.c源文件
(03) 设置断点,输入 b main
(04) 启动test程序,输入run
(05) 程序在main开始的地方设置了断点,所以程序在printf处断住
(06) 这时候,可以单步跟踪。s单步可以进入到函数,而n单步则越过函数
(07) 如果希望从断点处继续运行程序,输入c
(08) 希望程序运行到函数结束,输入finish
(09) 查看断点信息,输入 info break
(10) 如果希望查看堆栈信息,输入bt
(11) 希望查看内存,输入 x/64xh + 内存地址
(12) 删除断点,则输入delete break + 断点序号
(13) 希望查看函数局部变量的数值,可以输入print + 变量名
(14)希望修改内存值,直接输入 print + *地址 = 数值
(15) 希望实时打印变量的数值,可以输入display + 变量名
(16) 查看函数的汇编代码,输入 disassemble + 函数名
(17) 退出调试输入quit即可

linux下的C语言开发(AT&T 汇编语言)
同样是x86的cpu,但是却可以用不同形式的汇编语言来表示。
在window上面我们使用的更多是intel格式的汇编语言,而在Linux系统上面使用的更多的常常是AT&T格式的汇编语言。那什么是AT&T格式的汇编代码呢?我们可以写一个试试看。

.data
message: .string "hello!\n"
length = . - message
.text
.global _start
_start:
movl $length, %edx
movl $message, %ecx
movl $1, %ebx
movl $4, %eax
int $0x80
movl $0, %ebx
movl $1, %eax
int $0x80
08048074 &lt;_start>:
.text
.global _start
_start:
movl $length, %edx
8048074: ba 08 00 00 00 mov $0x8,%edx
movl $message, %ecx
8048079: b9 9c 90 04 08 mov $0x804909c,%ecx
movl $1, %ebx
804807e: bb 01 00 00 00 mov $0x1,%ebx
movl $4, %eax
8048083: b8 04 00 00 00 mov $0x4,%eax
int $0x80
8048088: cd 80 int $0x80
movl $0, %ebx
804808a: bb 00 00 00 00 mov $0x0,%ebx
movl $1, %eax
804808f: b8 01 00 00 00 mov $0x1,%eax
int $0x80
8048094: cd 80 int $0x80
ret
8048096: c3 ret

这是一个简单的汇编文件,我们可以分两步进行编译。首先,输入 as -gstabs -o hello.o hello.s, 接着输入ld -o hello hello.o即可。为了验证执行文件是否正确,可以输入./hello验证一下。
在as命令当中,由于我们使用了-gstabs选项,因此在hello执行文件中是包含调试信息的。所以,如果想单步调试的朋友可以输入gdb hello进行调试。
那么,hello执行文件反汇编的代码又是什么样的呢?我们可以输入objdump -S -d hello查看一下。

linux下的C语言开发(静态库)
在我们编写软件的过程当中,少不了需要使用别人的库函数。因为大家知道,软件是一个协作的工程。作为个人来讲,你不可能一个人完成所有的工作。另外,网络上一些优秀的开源库已经被业内广泛接受,我们也没有必要把时间浪费在这些重复的工作上面。
既然说到了库函数,那么一般来说库函数分为两种方式:静态库和动态库。两者的区别其实很小,静态库是必须要链接到执行文件中去的,而动态库是不需要链接到最后的执行文件中的。怎么理解呢?也就是说,对于最后的执行文件而言,你是否删除静态库无所谓。但是,一旦你删除了动态库,最后的执行文件就玩不转了。
今天我们讨论的问题是静态库。为了显示windows和linux创建静态库之间的差别,我们首先在windows上面利用Visual C++6.0创建一个静态库。源文件的代码很简单,

#include "test.h"
int add(int a, int b)
{
    return a + b;
}

头文件代码也不难,

#ifndef _TEST_H
#define _TEST_H
int add(int a, int b);
#endif

如果你需要在windows上面创建一个静态库,那么你需要进行下面的操作,
(1)打开visual C++ 6.0工具,单击【File】-> 【New】->【Projects】
(2)选择【Win32 Static Library】,同时在【Project Name】写上项目名称,在【Location】选择项目保存地址
(3)单击【Ok】,继续单击【Finish】,再单击【Ok】,这样一个静态库工程就创建好了
(4)重新单击【File】->【New】->【Files】,选择【C++ Source Files】,
(5)选中【Add to pproject】,将源文件加入到刚才创建的工程中去,在File中输入文件名+.c后缀
(6)重复4、5的操作,加入一个文件名+.h头文件
(7)分别在头文件和源文件中输入上面的代码,单击F7按钮,即可在Debug目录中生成*.lib静态库文件

那么,在linux下面应该怎么运行呢?其实很简单,两条命令解决,
(1)首先生成*.o文件,输入gcc -c test.c -o test.o
(2)利用ar命令生成静态库,输入ar rc libtest.a test.o

此时如果还有一个hello.c文件使用到了这个静态库,比如说 ,

#include &lt;stdio.h>
#include "test.h"
int main()
{
    printf("%d\n", add(2, 3));
    return 1;
}

其实也很简单,输入一个简单的命令就可以生成执行文件了,
(1)首先输入gcc hello.c -o hello ./libtest.a
(2)输入./hello,验证生成的执行文件是否正确
(3)朋友们可以删除libtest.a文件,重新输入./hello,验证执行文件是否可以正常运行

linux下的C语言开发(动态库)
动态链接库不是linux独有的特性,在windows下面也存在这样的特性。一般来说,windows下面的动态连接库是以.dll作为结尾的,而linux下面的动态连接库是以.so结尾的。和静态链接库相比,动态连接库可以共享内存资源,这样可以减少内存消耗。另外,动态连接是需要经过操作系统加载器的帮助才能被普通执行文件发现的,所以动态连接库可以减少链接的次数。有了这个特点,我们就不难发现为什么很多软件的补丁其实都是以动态库发布的。

那么,在Linux上动态库是怎么生成的呢?

#include "test.h"
int add(int a, int b)
{
    return a + b;
}

头文件格式,

#ifndef _TEST_H
#define _TEST_H
int add(int a, int b);
#endif

此时如果我们想要生成动态库,要做的工作其实非常简单,输入gcc -shared -fPIC -o libtest.so test.c即可。回车后输入ls,我们就可以发现当前目录下面出现了libtest.so文件。

#include &lt;stdio.h>
#include "test.h"
int main()
{
    printf("%d\n", add(2, 3));
    return 1;
}

在上面的代码当中,我们发现使用到了add函数,那么此时如何才能生成一个执行文件呢?也很简单,输入gcc hello.c -o hello ./libtest.so。然后输入./hello,此时可以验证一下执行文件运行是否正确。在编写静态库的时候,我说过静态库是汇编链接到执行文件当中的,而动态库不会。朋友们可以做个小实验,删除libtest.so,然后输入./hello。此时大家可以看看系统有没有错误返回?
这个时候,有的朋友就会问了,那在windows下面dll应该怎么编写呢?其实也不难,只要在test.h上面稍作改变即可。其他的步骤和静态库的操作是基本类似的。

#ifndef _TEST_H
#define _TEST_H
#ifdef USR_DLL
#define DLL_API _declspec(dllexport)
#else
#define DLL_API _declspec(dllimport)
#endif
DLL_API int add(int a, int b);
#endif

linux下的C语言开发(定时器)
定时器是我们需要经常处理的一种资源。那linux下面的定时器又是怎么一回事呢?其实,在linux里面有一种进程中信息传递的方法,那就是信号。这里的定时器就相当于系统每隔一段时间给进程发一个定时信号,我们所要做的就是定义一个信号处理函数。

#include &lt;stdio.h>
#include &lt;time.h>
#include &lt;sys/time.h>
#include &lt;stdlib.h>
#include &lt;signal.h>
static int count = 0;
static struct itimerval oldtv;
void set_timer()
{
    struct itimerval itv;
    itv.it_interval.tv_sec = 1;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = 1;
    itv.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &amp;itv, &amp;oldtv);
}
void signal_handler(int m)
{
    count ++;
    printf("%d\n", count);
}
int main()
{
    signal(SIGALRM, signal_handler);
    set_timer();
    while(count &lt; 10000);
    exit(0);
    return 1;
}

linux下的C语言开发(自动编译工具)
在Linux下面,编写makefile是一件辛苦的事情。因此,为了减轻程序员编写makefile的负担,人们发明了autoconf和automake这两个工具,可以很好地帮我们解决这个问题。
我们可以通过一个简单的示例来说明如何使用配置工具。

(1)首先,编写源文件hello.c。

#include &lt;stdio.h>
int main(int argc, char** argv[])
{
    printf("hello, world!\n");
    return 1;
}

(2)接下来,我们需要创建一个Makefile.am,同时编写上脚本。

SUBDIRS=
bin_PROGRAMS=hello
hello_SOURCES=hello.c

(3)直接输入autoscan,生成文件configure.scan,再改名为configure.in。修改脚本AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)为AC_INIT(hello, 1.0, feixiaoxing@163.com)同时,在AC_CONFIG_HEADER([config.h])后面添加AM_INIT_AUTOMAKE(hello, 0.1)
(4)依次输入aclocal命令、autoheader命令
(5)创建4个文件,分别为README、NEWS、AUTHORS和ChangeLog
(6)依次输入automake -a、autoconf命令
(7)输入./configure,生成最终的Makefile
(8)如果需要编译,输入make;如果需要安装, 输入make install;如果需要发布软件包,输入make dist

linux下的C语言开发(进程创建)
在Linux下面,创建进程是一件十分有意思的事情。我们都知道,进程是操作系统下面享有资源的基本单位。那么,在Linux下面应该怎么创建进程呢?其实非常简单,一个fork函数就可以搞定了。但是,我们需要清楚的是子进程与父进程之间除了代码是共享的之外,堆栈数据和全局数据均是独立的。

#include &lt;unistd.h>
#include &lt;stdio.h>
#include &lt;stdlib.h>
#include &lt;math.h>
#include &lt;errno.h>
#include &lt;sys/types.h>
#include &lt;sys/wait.h>
int main()
{
    pid_t pid;
    if(-1 == (pid = fork())) {
        printf("Error happened in fork function!\n");
        return 0;
    }
    if(0 == pid) {
        printf("This is child process: %d\n", getpid());
    } else {
        printf("This is parent process: %d\n", getpid());
    }
    return 0;
}

linux下的C语言开发(进程等待)
所谓进程等待,其实很简单。前面我们说过可以用fork创建子进程,那么这里我们就可以使用wait函数让父进程等待子进程运行结束后才开始运行。注意,为了证明父进程确实是等待子进程运行结束后才继续运行的,我们使用了sleep函数。但是,在linux下面,sleep函数的参数是秒,而windows下面sleep的函数参数是毫秒。

#include &lt;stdio.h>
#include &lt;stdlib.h>
#include &lt;unistd.h>
int main(int argc, char* argv[])
{
    pid_t pid;
    pid = fork();
    if(0 == pid) {
        printf("This is child process, %d\n", getpid());
        sleep(5);
    } else {
        wait(NULL);
        printf("This is parent process, %d\n", getpid());
    }
    return 1;
}

下面,我们需要做的就是两步,首先输入gcc fork.c -o fork, 然后输入./fork,就会在console下面获得这样的结果。

[root@localhost fork]# ./fork
This is child process, 2135
This is parent process, 2134

linux下的C语言开发(信号处理)
信号处理是linux程序的一个特色。用信号处理来模拟操作系统的中断功能,对于我们这些系统程序员来说是最好的一个选择了。要想使用信号处理功能,你要做的就是填写一个信号处理函数即可。一旦进程有待处理的信号处理,那么进程就会立即进行处理。

#include &lt;stdio.h>
#include &lt;stdlib.h>
#include &lt;signal.h>
int value = 0;
void func(int sig)
{
    printf("I get a signal!\n");
    value = 1;
}
int main()
{
    signal(SIGINT, func);
    while(0 == value)
        sleep(1);
    return 0;
}

为了显示linux对signal的处理流程,我们需要进行两个步骤。
第一,输入gcc sig.c -o sig, 然后输入./sig即可;
第二则重启一个console窗口,输入ps -aux | grep sig, 在获取sig的pid之后然后输入kill -INT 2082, 我们即可得到如下的输出。

[root@localhost fork]#./sig
I get a signal!
[root@localhost fork]#

linux下的C语言开发(管道通信)
Linux系统本身为进程间通信提供了很多的方式,比如说管道、共享内存、socket通信等。管道的使用十分简单,在创建了匿名管道之后,我们只需要从一个管道发送数据,再从另外一个管道接受数据即可。

#include &lt;stdio.h>
#include &lt;unistd.h>
#include &lt;stdlib.h>
#include &lt;string.h>
int pipe_default[2];
int main()
{
    pid_t pid;
    char buffer[32];
    memset(buffer, 0, 32);
    if(pipe(pipe_default) &lt; 0) {
        printf("Failed to create pipe!\n");
        return 0;
    }
    if(0 == (pid = fork())) {
        close(pipe_default[1]);
        sleep(5);
        if(read(pipe_default[0], buffer, 32) > 0) {
            printf("Receive data from server, %s!\n", buffer);
        }
        close(pipe_default[0]);
    } else {
        close(pipe_default[0]);
        if(-1 != write(pipe_default[1], "hello", strlen("hello"))) {
            printf("Send data to client, hello!\n");
        }
        close(pipe_default[1]);
        waitpid(pid, NULL, 0);
    }
    return 1;
}

下面我们就可以开始编译运行了,老规矩分成两步骤进行:
(1)输入gcc pipe.c -o pipe;
(2)然后输入./pipe,过一会儿你就可以看到下面的打印了。

[test@localhost pipe]$ ./pipe
Send data to client, hello!
Receive data from server, hello!

linux下的C语言开发(多线程编程)
多线程和多进程还是有很多区别的。其中之一就是,多进程是linux内核本身所支持的,而多线程则需要相应的动态库进行支持。对于进程而言,数据之间都是相互隔离的,而多线程则不同,不同的线程除了堆栈空间之外所有的数据都是共享的。说了这么多,我们还是自己编写一个多线程程序看看结果究竟是怎么样的。

#include &lt;stdio.h>
#include &lt;pthread.h>
#include &lt;unistd.h>
#include &lt;stdlib.h>
void func_1(void* args)
{
    while(1) {
        sleep(1);
        printf("this is func_1!\n");
    }
}
void func_2(void* args)
{
    while(1) {
        sleep(2);
        printf("this is func_2!\n");
    }
}
int main()
{
    pthread_t pid1, pid2;
    if(pthread_create(&amp;pid1, NULL, func_1, NULL)) {
        return -1;
    }
    if(pthread_create(&amp;pid2, NULL, func_2, NULL)) {
        return -1;
    }
    while(1) {
        sleep(3);
    }
    return 0;
}

和我们以前编写的程序有所不同,多线程代码需要这样编译,输入gcc thread.c -o thread -lpthread,编译之后你就可以看到thread可执行文件,输入./thread即可。

[test@localhost Desktop]$ ./thread
this is func_1!
this is func_2!
this is func_1!
this is func_1!
this is func_2!
this is func_1!
this is func_1!
this is func_2!
this is func_1!
this is func_1!

linux下的C语言开发(线程等待)
和多进程一样,多线程也有自己的等待函数。这个等待函数就是pthread_join函数。那么这个函数有什么用呢?我们其实可以用它来等待线程运行结束。

#include &lt;stdio.h>
#include &lt;pthread.h>
#include &lt;unistd.h>
#include &lt;stdlib.h>
void func(void* args)
{
    sleep(2);
    printf("this is func!\n");
}
int main()
{
    pthread_t pid;
    if(pthread_create(&amp;pid, NULL, func, NULL)) {
        return -1;
    }
    pthread_join(pid, NULL);
    printf("this is end of main!\n");
    return 0;
}

编写wait.c文件结束之后,我们就可以开始编译了。首先你需要输入gcc wait.c -o wait -lpthread,编译之后你就可以看到wait可执行文件,输入./wait即可。

[test@localhost thread]$ ./thread
this is func!
this is end of main!

linux下的C语言开发(线程互斥)
对于编写多线程的朋友来说,线程互斥是少不了的。在linux下面,编写多线程常用的工具其实是pthread_mutex_t。本质上来说,它和Windows下面的mutex其实是一样的,差别几乎是没有。希望对线程互斥进行详细了解的朋友可以看这里。

#include &lt;stdio.h>
#include &lt;pthread.h>
#include &lt;unistd.h>
#include &lt;stdlib.h>
static int value = 0;
pthread_mutex_t mutex;
void func(void* args)
{
    while(1) {
        pthread_mutex_lock(&amp;mutex);
        sleep(1);
        value ++;
        printf("value = %d!\n", value);
        pthread_mutex_unlock(&amp;mutex);
    }
}
int main()
{
    pthread_t pid1, pid2;
    pthread_mutex_init(&amp;mutex, NULL);
    if(pthread_create(&amp;pid1, NULL, func, NULL)) {
        return -1;
    }
    if(pthread_create(&amp;pid2, NULL, func, NULL)) {
        return -1;
    }
    while(1)
        sleep(0);
    return 0;
}

编写mutex.c文件结束之后,我们就可以开始编译了。首先你需要输入gcc mutex.c -o mutex -lpthread,编译之后你就可以看到mutex可执行文件,输入./mutex即可。

[test@localhost thread]$ ./mutex
value = 1!
value = 2!
value = 3!
value = 4!
value = 5!
value = 6!

linux下的C语言开发(网络编程)
不管在Windows平台下面还是在Linux平台下面,网络编程都是少不了的。在互联网发达的今天,我们的生活基本上已经离不开网络了。我们可以用网络干很多的事情,比如说IM聊天、FTP下载、电子银行、网络购物、在线游戏、电子邮件的收发等等。所以说,对于一个软件的开发者来说,如果说他不会进行网络程序的开发,那真是难以想象的。

在开始介绍网络编程的方法之前,我们可以回忆一下计算机网络的相关知识。目前为止,我们使用的最多网络协议还是tcp/ip网络。通常来说,我们习惯上称为tcp/ip协议栈。至于协议栈分成几层,有两种说法。一种是五层,一种是七层,我个人本身也比较倾向于五层的划分方法。大家可以通过下面的图看看协议栈是怎么划分的。

5、应用层
4、传输层
3、网络层
2、数据链路层
1、物理层

网络的不同层次实现网络的不同功能。物理层主要实现报文的成帧处理;数据链路层完成对报文的优先级的管理,同时实现二层转发和流量控制;网络层实现路由和转发的功能,一方面它需要实现对报文的fragment处理,另外一方面它还需要对路由信息进行处理和保存;传输层实现报文的发送和接受,它利用计数、时序、定时器、重发等机制实现对报文的准确发送,当然这都是tcp的发送机制,而udp一般是不保证报文正确发送和接收的;应用层就是根据传输层的端口信息调用不同的程序来处理传输的内容,端口8080是http报文,端口21是ftp报文等等。上面的逻辑稍显复杂,朋友们可以这么理解,
物理层关心的是如何把电气信号变成一段报文;数据链路层关心的是mac地址、vlan、优先级等;网络层关心的是ip地址,下一跳ip;传输层关心的是端口资源;应用层关心的是报文组装、解析、渲染、存储、执行等等。
目前关于tcp/ip完整协议栈的代码很多,其中我认为写得比较好的还是linux内核/net/ipv4下面的代码。如果朋友们对ipv6的代码感兴趣,也可以看看/net/ipv6的代码。档案如果朋友们对整个协议栈的代码结构理解得不是很清楚,可以参考《linux网络分析与开发》这本书。
当然,作为应用层,我们的其实考虑的不用这么复杂。对于网络程序编写人员来讲,所有网络的资源只要和一个socket关联在一起就可以了。当然在socket可用之前,我们需要为它配置端口信息和ip地址。配置完了之后,我们就可以慢慢等待报文的收发了。所以一般来说,作为服务器端口的处理流程是这样的,
a) 创建socket
b) 绑定socket到特定的ip地址
c) 对socket进行侦听处理
d) 接受socket,表明有客户端和服务器连接
e) 和客户端循环收发报文
f) 关闭socket

作为服务器程序而言,它要对特定的端口进行绑定和侦听处理,这样稍显复杂。但是如果是编写客户端的程序,一切的一切就变得非常简单了,
a) 创建socket
b) 链接服务器端地址
c) 和服务器端的socket收发报文

上面只是对网络编程做了一个基本的介绍,但是好多的东西还是没有涉及到,比如说:
(1) 什么时候该使用udp,什么时候该使用tcp?
(2) 如何把多线程和网络编程联系在一起?
(3) 如何把多进程和网络编程联系在一起?
(4) 如何利用select函数、epoll_create机制、非阻塞函数提高socket的并发处理效率?
(5) linux内核是怎么实现tcp/ip协议的?
(6) 我们自己是否也可以实现协议的处理流程等等?

参考文章:https://blog.csdn.net/weixin_40756041/article/details/88112872

Mysql跳过root密码,并修改root密码方法

1、跳过密码认证

 vim /etc/my.cnf
[mysqld]
skip-grant-tables      //指定位置加一行

改了配置文件,记得重启服务

systemctl restart mysqld       
mysql      //进入到mysql 

mysql> exit

二:更改root密码方式


1:第一种方式
直接在用Linux命令mysqladmin修改。

mysqladmin -u root password “123456”

ubuntu@server:~$ sudo mysqladmin -u root password “123456”
mysqladmin: [Warning] Using a password on the command line interface can be insecure.
Warning: Since password will be sent to server in plain text, use ssl connection to ensure password safety.


2:第二种方式
登录mysql 更改密码

ALTER USER ‘root’@’localhost’ IDENTIFIED BY ‘654321’;

mysql> ALTER USER ‘root’@’localhost’ IDENTIFIED BY ‘654321’;
Query OK, 0 rows affected (0.00 sec)

mysql>

3、消除跳过密码认证,进入正常mysql

vim /etc/my.cnf     

把刚刚添加的skip-grant-tables注释或者删除

同样,改了配置文件,要重启服务

 systemctl restart mysqld    

使用新密码登入

 mysql -uroot -p'123456'   

参考文章:https://cloud.tencent.com/developer/article/1661445
         https://blog.csdn.net/weixin_52270081/article/details/121539373

MySQL8中的lower_case_table_names忽略大小写配置

在MySQL数据库中我们可以通过配置 lower_case_table_names=1 来让其忽略大小写。在 MySQL 8 以下版本我们很好配置,但在 MySQL 8 中配置起来却有些麻烦。本文将尝试说明其中的问题,并给出解决方式。

lower_case_table_names 的作用

lower_case_table_names 的值:

  • 如果设置为 0,表名将按指定方式存储,并且在对比表名时区分大小写。
  • 如果设置为 1,表名将以小写形式存储在磁盘上,在对比表名时不区分大小写。
  • 如果设置为 2,则表名按给定格式存储,但以小写形式进行比较。

此选项还适用于数据库名称和表别名。有关其他详细信息,请参阅第 9.2.3 节 “标识符区分大小写“。

由于 MySQL 最初依赖于文件系统来作为其数据字典,因此默认设置是依赖于文件系统是否 区分大小写。

在 Windows 上,默认值为 1。在 macOS 上,默认值是 2。在 Linux 上,不支持值 2;服 务器会将该值设置为 0。

在不区分大小写的文件系统上(比如 Windows 或 macOS 中的文件系统),运行 MySQL 时 ,不应使用 --lower_case_table_names=0 。 这将是不受支持的组合。

如果尝试在不区分大小写的文件系统上使用--lower_case_table_names=0 启动服务器, 则会打印错误消息并退出服务器。

如果使用 InnoDB 表,则应在所有平台上将此变量设置为 1,以强制将名称转换为小写。

必须在初始化 MySQL 服务器(安装 MySQL 后的首次启动)之前将 lower_case_table_names 配置为所需的值。 在大多数情况下,这需要在首次启动 MySQL 服务器之前在 MySQL 配置文件中设置 lower_case_table_names 。

但是,当你在 Debian 和 Ubuntu 使用 APT 安装 MySQL 时,系统将自动为您初始化 MySQL,并且没有机会事先在配置文件中设置该值。因此,在使用 APT 安装 MySQL 之前, 必须使用 debconf-set-selection 实用程序来启用小写的表名。为此,请在使用 APT 安 装 MySQL 之前运行此命令(官方给出的命令,我没用过):

1shell> sudo debconf-set-selections <<< "mysql-server mysql-server/lowercase-table-names select Enabled

在 MySQL 8 中,数据目录初始化之后,不再允许更改 lower_case_table_names = 1 的 值;

MySQL 基于某些原因,禁止在重新启动 MySQL 服务时将 lower_case_table_names 设置 成不同于初始化 MySQL 服务时设置的 lower_case_table_names 值。

也就是说启动(重启)MySQL 时,lower_case_table_names的值必须于,初始化 MySQL 时(安装 MySQL 后的首次启动)的值相同。

这种限制是必要的,因为各种数据字典表字段使用的排序 规则基于服务器初始化时的设置,而使用不同设置重新启动服务器将导致标识符的排序和比 较方式不一致。

换一种说法: 一旦 MySQL 的数据目录被初始化后,该数据目录的中的标识符的排序和比较 方式就被确定;而使用不同设置重新启动 MySQL 服务器时,MySQL 服务器检测到其于数据 目录不匹配,将会报错。

如果您尝试使用与 MySQL 初始化时不同的lower_case_table_names值来启动 MySQL 8, 您将收到类似的错误:

1 2 3 4 5# lower_case_table_names 在数据目录的值为 0 ,而 mysql 服务器中的值为 1
2019-04-14T03:57:19.095459Z 1 [ERROR] [MY-011087] [Server] Different lower_case_table_names settings for server ('1') and data dictionary ('0').
2019-04-14T03:57:19.097773Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed.
2019-04-14T03:57:19.098425Z 0 [ERROR] [MY-010119] [Server] Aborting
2019-04-14T03:57:20.784893Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.15) MySQL Community Server - GPL.

安装 MySQL 8时配置不区分大小写

那么用 lower_case_table_names = 1 初始化 MySQL 8 的步骤是什么?

在 CentOS 中安装MySQL8:

  1. 添加 MySQL YUM repository (添加 MySQL 的 yam 仓库,略)
  2. 卸载当前系统中的其它 MySQL。(如果需要同时安装不同版本的 MySQL,请使用 tarball 发行版。)
  3. 清除数据目录: 为了能够初始化 MySQL,数据目录必须为空。 您可以选择对数据目录 使用非默认位置;也可以删除 /var/lib/mysql 目录。 如果要保留旧的数据目录,请 先进行备份!
  4. 安装 MySQL 8 :通过 yam install
  5. 初始化前指定 lower_case_table_names = 1: 方法,在初次使用 systemd 启动 mysqld 之前,在MySQL配置文件( /etc/my.cnf )中添加 lower_case_table_names=1
  6. 初始化: systemctl start mysqld

在 Debian 和 Ubuntu 中:

  • 与之类似,但在安装 MySQL 8 之前,需要借助 debconf-set-selections 运行上文讲 到过的命令。

为已安装的MySQL8设置不区分大小写

  • 停止MySQL
  • 删除数据目录,即删除 /var/lib/mysql 目录
  • 在MySQL配置文件( /etc/my.cnf )中添加 lower_case_table_names=1
  • 启动 MySQL

为Docker中的MySQL8容器设置不区分大小写

官方MySQL镜像,是基于 debian 系统的,FROM debian:buster-slim,并在该系统中使用 apt-get 安装 mysql-community-server ;详见其 Dockerfile

使用下面的方式运行 MySQL 8 容器:

设置字符集和排序方式

1docker run --name some-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

然后再来配置 mysql 8 忽略大小写:

  • 先使用上面的命令创建并运行容器 some-mysql
  • 在主机中创建配置文件,比如 /root/docker/mysql8/conf.d/config-file.cnf,文件内容如下:
[mysqld]
  lower_case_table_names = 1

  • 使用下面的命令将该文件复制到容器中
1docker cp /root/docker/mysql8/conf.d/config-file.cnf some-mysql:/etc/mysql/conf.d/
  • 停止容器
  • 删除数据目录,比如删除 /var/lib/mysql
  • 重启容器

参考文章

mysql错误:The MySQL server is running with the –skip-grant-tables option so it cannot execute this statement解决方法


本文为大家讲解的是mysql错误:The MySQL server is running with the –skip-grant-tables option so it cannot execute this statement解决方法,感兴趣的同学参考下。

错误描述:

mysql> grant all on cactidb.* to dbuser@’localhost’ identified by ‘123’;

ERROR 1290 (HY000): The MySQL server is running with the –skip-grant-tables option so it cannot execute this statement

解决方法:

先刷新一下权限表。

mysql> flush privileges;

Query OK, 0 rows affected (0.01 sec)

mysql> grant all on cactidb.* to dbuser@’localhost’ identified by ‘123’;

Query OK, 0 rows affected (0.00 sec)

原文博客的链接地址:https://cnblogs.com/qzf/

Debian初始化常用配置,及常用软件安装

开始配置:

1、配置sudo

Debian 11 安装完毕,首先需要授予当前用户sudo权限,否则无法进行系统升级、软件安装。

su root 输入管理员密码切换到root用户下  
vi /etc/sudoers

在# User privilege specification下添加如下内容(username为需要授予权限的用户)  

username ALL=(ALL:ALL) ALL  

如果要设置免密码sudo的话,添加如下内容
username ALL=(ALL:ALL) NOPASSWD:ALL  

然后输入:wq保存退出

2、配置右键打开终端参考文章

安装完后注销重新登录即可

sudo apt-get install caja-open-terminal

3、处理vi/vim无法用backspace删除和无法使用上下左右键移动的问题

sudo vi /etc/vim/vimrc.tiny

添加如下两行

set nocompatible
set backspace=2

4、处理vi/vim鼠标右键进入visual模式无法复制的问题参考文章

比较新的 Debian 系统中内置的 vim 也比较新,vim 有个默认的配置文件位于/usr/share/vim/vim80/defaults.vim,如果没有设置 $HOME/.vimrc 的话,vim 就会读取这个配置文件。

这个配置文件里有一项配置

if has(‘mouse’)  

set mouse=a

endif

导致 vim 默认为 visual 模式,与之前的默认模式不一致,操作不顺手。

我们可以自己新建一个 $HOME/.vimrc 写入自己想要的配置,比如代码高亮

if has(“syntax”)  

syntax on

endif

有了 $HOME/.vimrc 之后就不会读取 /usr/share/vim/vim80/defaults.vim 了。

也可以用shift+insert按键进行插入

5、关闭linux下的主板响声(主板蜂鸣器)

root模式下执行:(参考文章

rmmod pcspkr

echo “blacklist pcspkr” > /etc/modprobe.d/nobeep.conf

5、安装常用软件参考文章

Visual Studio Code(因VS Code开发版更新频繁,Debian 11 微软库速度太慢,所以安装稳定版)

1$ sudo dpkg -i code_1.60.2-1632313585_amd64.deb

FileZilla 开始 > 应用 > 系统 Discover 软件中心搜索下载

Dbeaver(点击可至官网下载)

1$ sudo dpkg -i dbeaver-ce_21.2.1_amd64.deb

WPS Office (点击可至官方网站)建议安装11.1.0.10161,11.1.0.10702提示系统分辨率缩放问题,显示有问题

1$ sudo dpkg -i wps-office_11.1.0.10161_amd64.deb

配置deepin仓库

wget -O- https://deepin-wine.i-m.dev/setup.sh | sh

微信

1# 首次使用,需添加deepin-wine仓库 $ sudo apt install com.qq.weixin.deepin

企业微信

1# 首次使用,需添加deepin-wine仓库 $ sudo apt install com.qq.weixin.work.deepin

QQ/TIM 当前版本TIM容易卡死自动关闭,所以最近在用QQ

TIM

1# 首次使用,需添加deepin-wine仓库 $ sudo apt install com.qq.office.deepin

QQ

1# 首次使用,需添加deepin-wine仓库 $ sudo apt install com.qq.im.deepin

百度网盘(点击可至官网下载)

安装前需要安装两个lib文件

wget http://ftp.de.debian.org/debian/pool/main/libi/libindicator/libindicator3-7_0.5.0-4_amd64.deb

sudo apt install ./libindicator3-7_0.5.0-4_amd64.deb

wget http://ftp.de.debian.org/debian/pool/main/liba/libappindicator/libappindicator3-1_0.4.92-7_amd64.deb

sudo apt install ./libappindicator3-1_0.4.92-7_amd64.deb

安装完lib,再安装百度网盘

sudo apt install ./baidunetdisk_3.5.0_amd64.deb

搜狗输入法

1$ sudo dpkg -i sogoupinyin_2.4.0.3469_amd64.deb

Yandex浏览器参考文章

要获取最新更新,建议从其官方APT存储库安装Yandex浏览器。 首先为Yandex浏览器创建源列表文件

sudo vim /etc/apt/sources.list.d/yandex-browser.list

将以下行添加到文件中。

deb [arch=amd64] http://repo.yandex.ru/yandex-browser/deb beta main

然后按:wq保存并退出

我们还需要下载并导入GPG密钥,以便可以验证从该存储库下载的软件包。

wget https://repo.yandex.ru/yandex-browser/YANDEX-BROWSER-KEY.GPG

sudo apt-key add YANDEX-BROWSER-KEY.GPG

之后,更新本地软件包索引并安装Yandex浏览器。

sudo apt update

sudo apt install yandex-browser-beta

安装后,您可以从Ubuntu Unity Dash或您喜欢的应用程序菜单启动它。

或从命令行。

yandex-browser

Debian 11系统安装

1. 启动镜像

启动镜像,进入安装界面,默认选择第一个图形化安装界面,回车

2. 选择语言

这里选择English语言,然后点击Continue

3.选择所在位置

4. 键盘布局

默认American English,然后点击Continue

5. 设置主机名

默认主机名(hostname)为debian,点击Continue

6. 设置域名

设置域名(Domain name)为jamysong,这里大家可以根据自己的来设定

7. 设置root账户密码

这里我设置root账户密码为root,大家根据自己的来设定,点击Continue

8. 设置用户和密码

(1)设置用户名

(2)设置密码

9. 设置时区

10. 磁盘分区

(1)选择Manual,进行手动磁盘分区模式,如果你不是太熟悉手动磁盘分区,可以选择第一个Guided-use entire disk,这样就可以自动分区了,我这里主要是介绍一下怎么手动进行磁盘分区

(2)选中你的磁盘,这里是53.7G这个,然后点击Continue

(3)选择yes开始创建分区,点击Continue

(4)创建boot(引导)分区

(I)选中下图所示分区,点击Continue

(II) 选中Create a new partition,点击Continue

(III) 输入分区大小,我这里设置的是1GB

(IV)设置分区类型为主分区(Primary)

(V)选择Done setting up the partition,完成boot分区参数设置,点击Continue

(5)创建swap虚拟分区

(I)选中下图所示分区,点击Continue

(II) 选中Create a new partition,点击Continue

(III) 输入分区大小,我这里设置的是2GB

(IV)设置分区类型为逻辑分区(Logical)

(V)选择Done setting up the partition,完成swap分区参数设置,点击Continue

(6) 创建根分区(/)

(I)选中下图所示分区,点击Continue

(II) 选中Create a new partition,点击Continue

(III) 输入分区大小,我这里设置的是剩下的所有,默认即可

(IV)设置分区类型为主分区(Primary)

(V)选择Done setting up the partition,完成swap分区参数设置,点击Continue

(7)执行分区方案,完成分区

这里主要是执行前面步骤中设定的分区方案,如果想重新进行分区,在这一步点击Continue之前还来得及,如果没有问题,直接点击Continue

(8)确认执行分区方案,进行写入磁盘操作

(9)如图所示正在执行分区操作并安装系统,耐心等待。。。。。。

11. 安装其他软件包

这里默认选择no,然后点击Continue

11. 安装系统镜像

这是询问是否使用网络镜像,默认选择no,然后点击Continue

12. 参与软件包使用情况调查

这里默认选择no,不用管这个,点击Continue继续往下走

13. 安装环境

这里选择安装环境,在默认基础上再勾选上SSH server,这个是为了后面可以进行用户ssh客户端软件进行连接,主要是为了方便命令操作和上传下载文件,然后点击Continue进入系统安装

14. 系统正在安装。。。。。

15. 安装引导程序

(1) 这里是安装系统引导程序,默认yes即可,点击Continue

(2) 这里选择你的磁盘就可以,然后点击Continue

16. 系统安装完成

走到这一步说明系统已经安装成功,点击Continue重启进入系统

17. 系统登录

这里直接点击用户名即可,如果你需要切换用户,点击Not listed?

输入用户密码,登录系统

到此登录真正的debian11界面了,大家可以尽情的玩耍了

终端输入cat /etc/os-release查看系统版本,这里确认是debian11

18. root用户登录

Debian安装完后,默认是不允许root用户直接登陆的,处于安全考虑,但是可以先通过普通用户登陆后再su root,然后输入root用户密码登录root用户,但是感觉这个还是比较麻烦的,下面介绍下通过修改配置文件来允许root用户直接登录,主要分两步:

(1)先用普通用户登录进系统,然后 su root,输入root密码切换到root用户,

直接nano /etc/gdm3/daemon.conf 文件,再security下面加上这么一行:AllowRoot = true,然后按Ctrl+X退出并保存,确认保存输入Y,最后按Ctrl+M退出即可

(2)nano /etc/pam.d/gdm-password文件,直接用#注释掉auth required pam_succeed_if.so user != root quiet_success这一行,然后按Ctrl+X保存,确认保存输入Y,再按Ctrl+M退出即可,最后重启系统可用root账户直接登录了

19. SSH登录

直接nano /etc/ssh/sshd_config文件,将PermitRootLogin 设置为yes,PasswordAuthentication设置为yes即可,然后重启sshd服务,就可以使用ssh客户端进行登录了

如下为Xshell登录界面

20. 修改镜像源文件

nano /etc/apt/sources/list文件,注释掉原有的内容,添加如下阿里云的镜像源,

deb http://mirrors.aliyun.com/debian/ bullseye main contrib

deb-src http://mirrors.aliyun.com/debian/ bullseye main contrib

deb http://mirrors.aliyun.com/debian/ bullseye-updates main contrib

deb-src http://mirrors.aliyun.com/debian/ bullseye-updates main contrib

deb http://mirrors.aliyun.com/debian/ bullseye-backports main contrib

deb-src http://mirrors.aliyun.com/debian/ bullseye-backports main contrib

deb http://mirrors.aliyun.com/debian/ bullseye-proposed-updates main contrib

deb-src http://mirrors.aliyun.com/debian/ bullseye-proposed-updates main contrib

然后按Ctrl+x保存,确认保存输入Y,最后按Ctrl+M退出,这时候可以执行apt-get update看下系统能否进行更新

参考链接:https://blog.csdn.net/u010080562/article/details/120246284