首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
80 阅读
2
nvim番外之将配置的插件管理器更新为lazy
58 阅读
3
2018总结与2019规划
54 阅读
4
PDF标准详解(五)——图形状态
33 阅读
5
为 MariaDB 配置远程访问权限
30 阅读
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
登录
Search
标签搜索
c++
c
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
VimScript
Java
emacs
linux
文本编辑器
elisp
反汇编
OLEDB
数据库编程
数据结构
内核编程
Masimaro
累计撰写
308
篇文章
累计收到
27
条评论
首页
栏目
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
页面
归档
友情链接
关于
搜索到
9
篇与
的结果
2025-03-28
Emacs 折腾日记(二十)——修改emacs的一些默认行为
上一篇我们完成了emacs输入法的配置以及将emacs配置成了使用vim的操作方式。但是emacs目前有些默认行为我不太喜欢,这节我们一起来修改它备份设置我们打开emacs的配置文件所在路径,发现有大量的~结尾的文件,这是emacs的备份文件。这里,我们不使用这个特性,可以通过git等版本管理软件进行版本的控制和备份的管理。而且去掉这些还能让目录干净点。(setq make-backup-files nil) ; 不自动备份 (setq auto-save-default nil) ; 不使用Emacs自带的自动保存将用户设置独立开来在修改这些配置的时候经常会发现在init.el 中出现类似下面的代码被修改(custom-set-variables ;; custom-set-variables was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(package-selected-packages nil)) (custom-set-faces ;; custom-set-faces was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. )这里保存的是使用编辑器接口产生的配置信息。如果让它们随意堆砌在init.el 中不利于版本的管理,我们将它放入到另一个文件中(setq custom-file (expand-file-name "~/.emacs.d/custom.el")) (load custom-file 'no-error 'no-message)之前我们用 require 来加载一个代码文件,这里我们使用 load 来加载代码文件。它们有什么区别呢?首先 require 需要加载一个已经被定义为库的代码文件,也就是通过 provide 定义的库文件。而load传入文件路径来加载其次 require 会根据 provide 定义的库文件自动处理库文件,每个库文件只加载一次,并且会自动处理依赖。而 load 这些操作都需要手动进行load 可以根据if条件来有选择的加载不同的库文件。而 require 则无法做到load 可以进行错误处理,例如上面我们定义在加载时通过 noerror 限制错误,通过 no-message 不输出信息。而 require 是严格报错的。其他的一些基础设置这里再添加一些其他的基础配置(fset 'yes-or-no-p 'y-or-n-p) ;; 将所有的 yes-or-no-p 都替换为 y-or-n-p (setq confirm-kill-emacs #'y-or-n-p) ; 在关闭 Emacs 前询问是否确认关闭,防止误触 (electric-pair-mode t) ; 自动补全括号 (column-number-mode t) ; 在 Mode line 上显示列号 (global-auto-revert-mode t) ; 当另一程序修改了文件时,让 Emacs 及时刷新 Buffer (delete-selection-mode t) ; 选中文本后输入文本会替换文本(更符合我们习惯了的其它编辑器的逻辑) (add-hook 'prog-mode-hook #'hs-minor-mode) ; 编程模式下,可以折叠代码块 (add-hook 'prog-mode-hook #'show-paren-mode) ; 编程模式下,光标在括号上时高亮另一个括号(fset 'yes-or-no-p 'y-or-n-p) 将所有的 yes-or-no-p 都替换为 y-or-n-p。这样在每次确定的时候能从 yes 或者 no的输入变成输入 y 或者 n,能少输入几个字符。这里又看到了一个新的符号# ,它代表的意思是取符号的函数部分。前面我们介绍符号的时候说,符号有两个部分的值,变量值和函数值。我们可以通过 function 来获取符号的函数部分的值。它的作用等同于 `(setq confirm-kill-emacs (function y-or-n-p))` 。这里又有一个新的函数 function。我们在介绍符号的时候介绍过使用 symbol-function 来获取符号的函数,那么他们两个有什么区别呢?首先 function 返回的是函数对象,而 symbol-function 返回函数本身。这个比较的抽象,我们使用例子来说明(setq bar "I am a bar variable") (defun bar() "I am a bar function") (function bar) ;; ==> bar (symbol-function 'bar) ;; ==> #[nil ("I am a bar function") (t)] (functionp bar) ;; ==> nil (functionp (function bar)) ;; ==> t上面的例子中,我们实际上定义了bar的变量部分和函数部分的值。同一 bar 符号它既可以作为变量使用,也可以作为函数使用。我们在使用 function 对 bar 求值的时候,得到的返回虽然也是 bar 但是它返回的是它的函数部分,而 symbol-function 则直接返回函数的结构,因为lisp代码本身就是一个列表结构,所以这里它返回的实际上是函数的代码。它返回的比 function 更加的底层。下面我们使用 functionp 进行了测试,发现 function 返回的是一个函数对象。虽然在理解上有些差别,但是都可以直接通过 funcall 来调用(bar) ;; ==> "I am a bar function" (funcall bar) ;; ==> error (funcall (function bar)) ;; ==> "I am a bar function" (funcall (symbol-function 'bar)) ;; ==> "I am a bar function"我们发现当一个符号既有值部分,又有函数部分,是无法通过 funcall 来直接调用的。所以上述代码使用 # 这个语法糖来保证后续正常调用这个符号对应的函数部分。
2025年03月28日
8 阅读
0 评论
0 点赞
2025-03-25
Emacs 折腾日记(十九)——配置输入法和vim操作方式
上一篇文章中,我们将Emacs变得稍微好看了点。换成了自己喜欢的主题和颜色,这样每天用起来也比较养眼,不会特别排斥。本篇文章的主要任务就是配置输入法方便输入中文以及将vim的操作模式搬到Emacs中。进一步提到Emacs的可用性配置中文输入法系统基本环境配置在配置输入法之前,需要系统支持中文,并且有对应的中文字体可以显示中文,而且还需要对应的输入法框架支持。首先我们安装中文字体和语言包,本人之前有一篇介绍如何搭建wsl2+archlinux的文章,已经完成了这一步。但是为了没看过那篇文章的读者不用再去费劲的找那篇文章,我还是把命令贴出来:sudo pacman -S wqy-zenhei wqy-microhei noto-fonts-cjk # 安装中文字体 sudo pacman -S fcitx5-im fcitx5-chinese-addons # 安装中文输入法框架及中文引擎 sudo pacman -S fcitx5-qt fcitx5-gtk # GUI支持接着配置 Locale ,我们需要编辑 /etc/locale.gen 文件,取消下面两行的注释en_US.UTF-8 UTF-8 zh_CN.UTF-8 UTF-8编辑完成之后,调用 sudo locale-gen 命令生成 locale。接着我们需要在 ~/.bashrc 或者 ~/.zshrc 又或者其他shell的配置文件中加入输入法的配置export GTK_IM_MODULE=fcitx5 export QT_IM_MODULE=fcitx5 export XMOIFIERS=@im=fcitx5然后我们启动fcitx5服务dbus-launch fcitx5 --disable=wayland -d &这个时候我们可以启动emacs,并且执行 M-x toggle-input-method 或者使用 C-\ 来切换输入法。只是默认的 chinese-py 输入法比较难用。所以我们需要换一个输入法并且给出拼音的词库emacs-rime 配置这个配置是我在 Emacs-China论坛 的一篇文章中发现这个输入法。可以访问 输入法源代码地址 ,它已发布到 Melpa,所以我们可以通过use-package 或者emacs自带的package来安装和管理。这里还是使用 use-package在安装之前,需要安装librime 和 fcitx5-rime。在arch中使用sudo pacman -S librime fcitx5-rime接着安装雾凇拼音,但是根据emacs-rime 官方文档的说法,最好不要将~emacs-rime~ 与 ~fcitx-rime~ 共用用户数据目录。所以这里我们我们将它放到其他目录git clone https://github.com/iDvel/rime-ice ~/.config/rime --depth=1然后我们进行emacs-rime的配置和安装(use-package rime :ensure t :custom (default-input-method "rime") (rime-posframe-properties (list :background-color "#333333" :foreground-color "#dcdccc" :font "WenQuanYi Micro Hei Mono-14" :internal-border-width 10)) (rime-user-data-dir "~/.config/rime") (rime-show-candidate 'posframe))到这里我们使用 C-\ 就可以愉快的输入中文了Vim 操作方式本系列文章并没有像一般的Emacs教程那样给各位读者介绍Emacs的操作和快捷键。因为我觉得Emacs可以很方便的变成跟vim一样的编辑器,既然读者们都熟悉vim,那就没必要单独的学习一套Emacs操作,直接继承vim的操作就行。这里说一个题外话,我觉得一个编辑器如果不支持vim的操作模式,要么就是使用的人不多,要么就是不够开放。对我来说这种编辑器平时就没有学习和使用的必要了。我们使用evil 插件来模拟vim的操作。(use-package evil :ensure t :init (evil-mode))我们执行完这句代码之后会发现已经进入了vim的normal模式了。这个时候又可以愉快的使用vim的操作方式来编辑文本了。但是查阅了关于evil的文档后发现,evil本身并不支持像vim那样设置leaderkey,我们要结合其他插件来达到这一效果。我们使用 general 插件来模拟并设置leaderkey(use-package general :ensure t :config (general-evil-setup t))插件安装完成之后可以使用下面的代码来设置leaderkey(general-create-definer my-leader-def :states '(normal insert visual emacs) :prefix "SPC" :non-normal-prefix "C-,")这里使用 general 提供的 general-create-definer 来定义自己的leader键,它可以定义leader键的作用范围和触发方式。my-leader-def 是一个符号它代表着我们在这里定义的leader键,后续可以通过它来结合其他按键来实现快捷键绑定。这里的 :states 表示作用的范围,在启用evil插件之后我们在 normal、insert、visual、emacs 这几个模式中启用这个leader键。通过 :prefix 定义leader键,这里我定义leader键为空格。最后一个参数 :non-normal-prefix 定义在非normal 模式下使用 C-, 来作为leader键。后面我们就可以通过这个 my-leader-def 这个符号来绑定快捷键了。下面提供一个例子来演示如何绑定快捷键。前面介绍vim相关内容的时候提到过,我们使用 <leader>ee 来快速打开配置文件,使用 <leader>ss 来重新加载配置,在这里实现以下emacs版本的这套功能。我们先来实现这两个功能函数(defun open-my-emacs-config() (interactive) (find-file "~/.emacs.d/init.el")) (defun source-my-emacs-config() (interactive) (eval-buffer (get-buffer "~/.emacs.d/init.el")))实现了这样的函数之后就是针对这些命令来绑定快捷键了。我们使用下面的代码来绑定(my-leader-def "ss" 'open-my-emacs-config) (my-leader-def "ee" 'source-my-emacs-config)至此我们使用evil 和 general 插件完成了一个简单的Emacs vim化的改造。利用这些简单的配置后面在使用的时候应该会更加的得心应手。随着代码越来越多,需要用git管理起来,每篇文章更新的代码我都会传到GitHub上供读者参考本篇代码
2025年03月25日
7 阅读
0 评论
0 点赞
2025-03-11
Emacs 折腾日记(十六)——文本操作
作为一个文本编辑器,编辑文本是最基本,也是最重要的功能。本文将介绍关于文件操作的一系列操作,比如查找文件,读写文件,文件信息、读取目录、文件名操作等。在之前关于vim的介绍时,已经详细的介绍过关于文件、缓冲和窗口的关系。相信各位读者不会弄混这些概念。在emacs从硬盘上读取文件到缓冲并且显示的过程与vim类似。只是vim会根据后缀设置file type,并根据file type加载相关配置和代码。而emacs会加载各种mode和mode的配置。文件读写从硬盘读取一个文件可以使用快捷键 C-x C-f ,它对应的命令是 find-file。它的主要作用是从输入的路径中找到硬盘上存储的文件,并且从文件中读取内容到缓冲区,然后显示缓冲区到窗口。保存缓冲到文件可以使用 C-x C-s,它对应的命令是 save-buffer。它会将当前缓冲写入到指定的文件中。在打开文件的过程中,会调用 find-file-noselect,它是打开文件的核心操作,与 find-file 不同,它只返 回访问文件的缓冲区。这两个函数都有一个特点,如果 emacs 里已经有一个缓冲 区访问这个文件的话,emacs 不会创建另一个缓冲区来访问文件,而只是简单返 回或者转到这个缓冲区。(find-file "~/.zshrc") ;; ==> #<buffer .zshrc> ;; 等效与 find-file (progn (setq foo (find-file-noselect "~/.zshrc")) (set-window-buffer nil foo))如何判断一个缓冲区是否关联了一个文件呢?每个和文件关联的缓冲区都有一个对应的 buffer-local 变量 buffer-file-name。但是不要直 接设置这个变量来改变缓冲区关联的文件。而是使用 set-visited-file-name 来 修改。同样不要直接从 buffer-list 里搜索buffer-file-name 来查找和某个文件关联的缓冲区。应该使用get-file-buffer 或者 find-buffer-visiting(setq foo (find-file-noselect "~/.zshrc")) (buffer-file-name foo) ;; ==> "home/xxx/.zshrc" (get-file-buffer "~/.zshrc") ;; ==> #<buffer .zshrc> (find-buffer-visiting "~/.zshrc") ;; ==> #<buffer .zshrc在打开文件过程中会调用 find-file-hook。这里的hook有点像vim中的事件,之前聊到过vim的自动命令,自动命令需要绑定到事件上触发。emacs中有大量的hook,我们通过在hook中添加一些操作来达到这个修改emacs默认行为或者增加新行为的特性。这个我们在后面再说。另外保存文件会调用一些hook和函数,保存文件之前会调用 before-save-hook,保存之后会调用 after-save-hook。一般来说,在配置emacs的时候,如果需要使用这些函数来读取文件,一般是读取上次退出时保存的临时文件,例如保存工程窗口布局的session文件。这些我们希望读取完成之后不将它们保留到buffer中。这个需求使用 find-file-noselect 是做不到的。必须使用更底层的函数。可以使用 insert-file-contents 和 write-region(insert-file-contents filename &optional visit beg end replace) (write-region start end filename &optional append visit lockname mustbenew)insert-file-contents 可以插入文件中指定部分到当前缓冲区中。如果指定 visit 则会标记缓冲区的修改状态并关联缓冲区到文件,一般是不用的。 replace 是指是否要删除缓冲区里其它内容,这比先删除缓冲区其它内容后插入文 件内容要快一些,但是一般也用不上。insert-file-contents 会处理文件的编 码,如果不需要解码文件的话,可以用 insert-file-contents-literally。write-region 可以把缓冲区中的一部分写入到指定文件中。如果指定 append 则是添加到文件末尾。和 insert-file-contents 相似,visit 参数也会把缓冲 区和文件关联,lockname 则是文件锁定的名字,mustbenew 确保文件存在时会 要求用户确认操作文件信息文件是否存在可以使用 file-exists-p 来判断。对于目录和一般文件都可以用 这个函数进行判断,但是符号链接只有当目标文件存在时才返回 t。如何判断文件是否可读或者可写呢?file-readable-p、file-writable-p, file-executable-p 分用来测试用户对文件的权限。文件的位模式还可以用 file-modes 函数得到(file-readable-p "~/.zshrc") ;; ==>t (file-writable-p "~/.zshrc") ;; ==>t (file-executable-p "~/.zshrc") ;; ==>nil (file-modes "~/.zshrc") ;; ==> 420文件类型判断可以使用 file-regular-p、file-directory-p、file-symlink-p, 分别判断一个文件名是否是一个普通文件(不是目录,命名管道、终端或者其它 IO 设备)、文件名是否一个存在的目录、文件名是否是一个符号链接。其中 file-symlink-p 当文件名是一个符号链接时会返回目标文件名。文件的真实名字也就是除去相对链接和符号链接后得到的文件名可以用 file-truename 得到。 事实上每个和文件关联的 buffer 里也有一个缓冲区局部变量 buffer-file-truename 来记录这个文件名。文件更详细的信息可以用 file-attributes 函数得到。这个函数类似系统的 stat 命令,返回文件几乎所有的信息,包括文件类型,用户和组用户,访问日 期、修改日期、status change 日期、文件大小、文件位模式、inode number、 system number临时文件如果要产生一个临时文件,可以使用 make-temp-file 这个函数按给定前缀产 生一个不和现有文件冲突的文件,并返回它的文件名。如果给定的名字是一个相 对文件名,则产生的文件名会用 temporary-file-directory 进行扩展。也可以用这个函数产生一个临时文件夹。如果只想产生一个不存在的文件名,可以用 make-temp-name 函数(make-temp-file "foo") (make-temp-name "foo")读取目录内容可以用 directory-files 来得到某个目录中的全部或者符合某个正则表达式的 文件名。;; 获取用户目录的文件名称 (directory-files "~/") ;; 获取用户目录的文件全路径 (directory-files "~/") ;; 获取目录中所有cpp文件 (directory-files "~/demo/src" t "\\.cpp$")另外也可以写一段简单的代码来遍历某个路劲下所有文件(defun my-list-files (dir) "递归遍历目录 DIR 下的所有文件并返回路径列表。" (let ((files (directory-files dir t "^[^.]")) (result '())) (dolist (file files result) (if (file-regular-p file) (push file result) (when (and (file-directory-p file) (not (file-symlink-p file)) (file-readable-p file)) (setq result (append result (my-list-files file)))))))) (my-list-files "~/.emacs.d")在调用 directory-files 的时候通过一个正则表达式过滤掉所有以.开头的文件,这里主要是为了过滤掉 . 和 .. 防止进入无线递归。但是它也误伤了所有隐藏文件。后面就是比较常规的操作了,遍历返回的list,如果是文件则加入到现有结果集中,如果是目录则进入递归。directory-files-and-attributes 和 directory-files 相似,但是返回的列表 中包含了 file-attributes 得到的信息。file-name-all-versions 用于得到某个文件在目录中的所有版本,file-expand-wildcards 可以用通配符来得到目录中的文件列表。修改文件信息重命名和复制文件可以用 rename-file 和 copy-file。删除文件使用 delete-file。创建目录使用 make-directory 函数。不能用 delete-file 删除 目录,只能用 delete-directory 删除目录。当目录不为空时会产生一个错误。设置文件修改时间使用 set-file-times。设置文件位模式可以用 set-file-modes 函数。set-file-modes 函数的参数必须是一个整数。你可以用位 函数 logand、logior 和 logxor 函数来进行位操作。(set-file-modes FILENAME MODE &optional FLAG)其中mode是数字,数字的含义与与chmode 命令类似,例如下面的调用(set-file-modes "example.txt" #o740)
2025年03月11日
6 阅读
0 评论
0 点赞
2025-02-19
Emacs折腾日记(十三)——函数、宏以及命令
之前在开篇介绍简单的elisp时候就提到过函数,后面的一些示例中也用到了一些函数,但是都是一些基本的概念,这篇将深入了解函数的一些特性。首先要判断一个符号是否是函数,可以使用 functionp 来判断。(defun foo() 1) (foo) (functionp 'foo) ;; ==> t (setq var 1) (functionp 'var) ;; ==> nil不光函数,以下几种functionp也返回t函数。这里的函数特指用 lisp 写的函数。原子函数(primitive)。用 C 写的函数,比如 car、append。lambda 表达式特殊表达式宏(macro)。宏是用 lisp 写的一种结构,它可以把一种 lisp 表达式转换成等价的另一个表达式。命令。命令能用 command-execute 调用。函数也可以是命令。参数列表的语法过去我们的所有函数都是定参的函数,也就是说是确定了参数个数的函数。但是实际使用中会大量使用不定参函数,也就是参数不确定的函数。在C/C++ 以及 Python中会大量使用。它的一个使用场景就是某些时候不传就采用默认值,否则就采用用户定义的值。另一个场景就是像printf这样事先无法确定到底要输出多少内容。elisp中的函数完整定义如下(defun func (REQUIRED-VARS... [&optional OPTIONAL-VARS...] [&rest REST-VAR]))前面是确定的参数列表,也就是说前面的参数在调用函数时必须传入,而&optional 之后是可选参数,如果要传入可选参数这个 &optional 关键字是必须写上的。这里的可选参数也是需要在定义时一个个的指定出来,但是&rest 之后定义的只用一个变量来使用,在传入的时候可以传入任意个参数。例如下面的例子(defun foo (var1 var2 &optional op1 op2 &rest rest) (list var1 var2 op1 op2 rest)) (foo 1 2) ;; ==> (1 2 nil nil nil) (foo 1 2 3) ;; ==> (1 2 3 nil nil) (foo 1 2 3 4) ;; ==> (1 2 3 4 nil) (foo 1 2 3 4 5) ;; ==> (1 2 3 4 (5)) (foo 1 2 3 4 5 6) ;; ==> (1 2 3 4 (5 6))从这个例子我们可以得出以下几个结论:当可选参数没有提供时,在函数体里,对应的参数值都是 nil。我们可以通过判断是否为nil来判断用户是否传了参&rest 要捕获后面所有传入的参数,所以它必须在参数列表的最后面,它的值是一个list当 &rest 与 &optional 共存时,优先匹配 &optional 参数,最后如果有剩余的参数则分配给 &rest教程原文中是有关于文档字符串的描述的。但是我想现在我作为一个菜鸟,将来要组织自己的配置也主要依靠拷贝粘贴别人现有的东西再组合,没有多少机会参与那种高大上的开源项目,自己将来弄的配置估计也没什么人用,而且我也会详细记录自己攒配置的过程,所以这里就不需要给函数写过于详细的文档说明。这里我就跳过这块了。如果有读者对这块感兴趣可以看原文。函数调用在编写程序的时候会有这种需求,一个框架负责处理大块的内容,比如数据解析、转发等等,它会预留一些接口来让用户在此基础之上处理自己的业务逻辑,比较典型的就是http server,或者gui程序框架。在C/C++ 中一般会预留一些函数指针类型的参数进行回调或者提供接口供使用方重载实现自己的逻辑。在elisp中也有这样的操作,但是它就没有虚函数、虚基类或者函数指针的概念。在elisp中通过符号调用一个函数使用的方法是 funcall 和 apply。它们都是通过符号来调用函数的,唯一的区别在于如何处理传入参数。我们通过一个例子来看看它们有什么不同。我们还是用上面定义的foo函数来测试(funcall 'foo 1 2 3 4 5 6) ;; ==> (1 2 3 4 (5 6)) (apply 'foo 1 2 3 4 5 6) ;; ==> error (apply 'foo 1 2 3 4 '(5 6)) ;; ==> (1 2 3 4 (5 6)) (apply 'foo 1 2) ;; ==> error (apply 'foo '(1 2)) ;; ==> (1 2 nil nil nil) (apply 'foo 1 2 3 4) ;; ==> error (apply 'foo 1 2 '(3 4)) ;; ==> (1 2 3 4 nil) (apply 'foo 1 2 3 4 5) ;; ==> error (apply 'foo 1 2 3 4 '(5)) ;; ==> (1 2 3 4 (5))从上面的结果可以看出,funcall 直接按照对应函数定义的参数列表进行传参即可。而apply在传参的时候最后一个参数必须是list,并且在嗲用时会自动将list参数给展开并传入各个参数。从上面的区别可以看出,如果在调用函数的时候,参数已经通过list进行了组织的话,那么使用apply更为合适,否则使用funcall。宏宏是lisp家族中一个非常重要,也非常灵活的内容,可以说宏是lisp的灵魂。之前在看到一些lisp相关的教程时都说,宏实现了利用代码生成代码,并且因为宏的存在导致lisp中扩展出了大量的方言。可以说没有宏,lisp就不是lisp了,或者说lisp就没这么灵活了。但是C/C++中也有宏的概念,C/C++中的宏是在预处理阶段进行简单的文本替换,然后编译替换之后的结果。虽然利用宏,C/C++中可以实现很多非常复杂的功能,但是它远远没有lisp的宏灵活。要详细了解宏的相关内容,我们先回忆一下之前介绍的elisp的知识。首先elisp或者lisp的代码本身就是一颗语法树。它被写作一个list。也就是说list既可以作为代码执行,也可以作为数据,例如 (setq x 1) 它是一段代码。而 '(setq x 1) 它是一个列表,列表中有3个元素,分别是 setq 、x、1 这么三个符号和数字。再者elisp特有的符号系统,例如 x 表示一个变量,可以对它进行求值,'x 代表一个符号,根据前面所学的,我们可以通过符号找到符号中记录的值、函数、属性等等。基于这两个内容,我们可以通过操作list来实现生成一段代码。例如下列的例子(defun my-inc (var) (list 'setq var (list '1+ var))) (setq x 0) (eval (my-inc 'x)) ;; ==> 1上面的其实就是返回了一个list, (setq var (1+ var))。后面我们通过 eval 来执行这个返回的list。需要注意的时,函数调用时会首先将变量进行求值,然后将值作为参数传入,但是这里我们希望并不希望传入一个具体的值,而是希望他能操作我们传入的变量值,并改变它,要做到这点需要传入一个符号。这里有点像C++ 中的引用传递定义宏其实跟定义函数非常相似。我们只需要将关键字由 defun 改为 defmacro。(defmacro my-inc(var) (list 'setq var (list '1+ var))) (setq x 0) (my-inc x) ;; ==> 1我们发现宏与函数的一个不同点,函数中代码在函数被调用时执行,并且参数是在调用时进行求值并传入。而宏调用时需要展开它返回的表达式(或者这里直接就是一个list)。然后将参数作为符号传入。宏最后需要返回一段可执行的list数据,如果没有返回,会影响展开执行,最终可能会报错,例如下面的例子(defmacro my-inc (var) (setq var (1+ var))) (setq x 0) (my-inc x) ;; ==> error这里的问题在于这个宏定义的代码是一个直接执行的代码,并不是一个list,所以在调用它的时候会直接执行,但是又需要将参数作为符号绑定,所以它在被调用的时候会执行(setq 'x (1+ 'x)) 这段代码,而这里的x是一个符号,无法直接对符号进行赋值,所以它会报x的类型错误。这里已经显示出了,elisp中的宏与C/C++中宏的不同。首先C/C++中的宏只是简单的字符串替换,可以将它理解为它生成了新的C/C++源码的代码,它在预处理阶段来执行代码的替换。而elisp中并没有简单的进行替换,根据之前介绍lisp表达式的解析,其实宏返回的是一颗抽象语法树。在扩展宏的时候不断的进行抽象语法树的修改和重建,最后在执行的时候将传入的参数作为符号放入到这颗树中的对应节点。我们可以使用 macroexpand 来查看宏展开的样子。(defmacro bad-inc (var) (setq var (1+ var))) (macroexpand '(bad-inc 0)) ;; ==> 1我们发现之前错误的实现并没有生成可执行的代码,而是直接返回一个常数。因为宏中的代码首先在展开的时候就已经执行了。相当于返回了 setq var (1+ 0) 的值,也就是1。(defmacro my-inc (var) (list 'setq var (list '1+ var))) (macroexpand '(my-inc x)) ;; ==> (setq x (1+ x))使用 macroexpand 可以使宏的编写变得容易一些。但是如果不能进行 debug 是很不方便的。在宏定义里可以引入 declare 表达式,它可以增加一些信息。目前只支持两类声明:debug 和 indent。debug 可选择的类型很多,具体参考 info elisp - Edebug 一章,一般情况下用 t 就足够了。indent 的类型比较简单,它可以使用这样几种类型:nil 也就是一般的方式缩进defun 类似 def 的结构,把第二行作为主体,对主体里的表达式使用同样的缩进整数 表示从第 n 个表达式后作为主体。比如 if 设置为 2,而 when 设置为 1符号 这个是最坏情况,你要写一个函数自己处理缩进。从前面的例子就可以看到,如果在定义宏的时候使用list cons 等来构建list是非常麻烦的,一旦要构造非常复杂的程序,可能直接就歇菜了。为了方便,elisp中提供了一些符号来简化操作。 ` 读作backquote,表示被它包裹的表达式都是quote,可以理解为它里面的直接构建了一个list如果希望它里面的某个位置不作为quote的一部分,而是直接作为列表的元素,可以使用 , , 也就是它会对后面的内容进行求值如果要让一个列表作为整个列表的一部分(slice),可以用 ",@",它会将后面的内容作为列表参数依次添加到当前列表中。我想起来了之前接触过的quote,也就是 ' 。它表示后面的内容不进行求值,作为符号,虽然它也可以构造一个list,但是二者还是有些不同,例如'(list x (+ 1 2)) ;; ==> (list x (+ 1 2)) `(list x (+ 1 2)) ;; ==> (list x (+ 1 2)) '(list x ,(+ 1 2)) ;; ==> (list x (\, (+ 1 2))) `(list x ,(+ 1 2)) ;; ==> (list x 3) (setq var '(2 3)) '(list x ,@var) ;; ==> (list x (\,@ var)) `(list x ,@var) ;; ==> (list x 2 3)我们使用上面的方法稍微弄一个复杂一点的宏(defmacro max(a b) `(if (> ,a ,b) ,a ,b)) (max 4 5) (max (1+ 2) (+ 3 6)) '(macroexpand '(max (1+ 2) (+ 3 6))) ;; ==> (if (> (1+ 2) (+ 3 6)) (1+ 2) (+ 3 6))这里是一个经典的C/C++ 中的max宏。虽然实现不严谨,有一些副作用,但是可以从上面看到一些用法。首先使用 ` 表示返回一个列表,以供调用的时候进行展开。再者对于传入的a和b需要使用, 来表示需要求解它们的值,实现参数的绑定,否则将会得到一个错误,例如(defmacro max(a b) `(if (> a b) a b)) (macroexpand '(max 4 5))) ;; ==> (if (> a b) a + b)如果将上述的 , 全部替换成 ,@ 就不太合适了,因为 ,@ 是将列表中的值取出来组成新的列表,并不会想 , 那样进行求值。例如(defmacro max(a b) `(if (> ,@a ,@b) ,@a ,@b)) (macroexpand '(max (1+ 2) (+ 3 6))) ;; ==> (if (> 1+ 2 + 3 6) 1+ 2 + 3 6)命令emacs 运行时就是处于一个命令循环中,不断从用户那得到按键序列,然后调用对应命令来执行。emacs 中的命令可以说就是一个函数,它是一个特殊的函数,是里面包含了 interactive 表达式的函数。这个表达式指明了这个命令的参数。比如下面这个命令(defun say-hello (name) (interactive "swhat's your name:") (message "hello, %s" name))当解释器加载了该函数之后就可以使用 M-x 来调用这个函数。我们根据提示输入一个名字,emacs会在minibuffer中输出一段话。我们发现,在interactive 表达式后面跟的字符串前面多了一个 s 字符。我们可以通过这个多加的字符来控制命令参数的类型和行为,例如使用 s 表示字符串参数,n 表示数字参数,f 代表文件,r 代表区域。interactive 的字符十分复杂,而且繁多。用的时候看 interactive 函数的文档还是很有必要的。但是不是所有时候都参数类型都能使用代码字符,而且一个好的命令,应该尽可能的让提供默认参数以让用户少花时间在输入参数上,这时,就有可能要自己定制参数。首先学习和代码字符等价的几个函数。s 对应的函数是 read-string,n 代表的是 read-file,f代表的是 read-file-name。其实大部分代码字符都是有这样对应的函数或替换的方法。我们可以使用这些方法来替代前面的代码字符,假如传入的是一个表达式,那么对表达式进行计算之后返回的列表元素就是命令的参数,例如我们用 read-string 来代替之前例子中的s。(defun say-hello (name) (interactive (list (read-string "what's your name: "))) (message "hello, %s" name))教程 中还列举了一些常见的字符代表的函数,这里我就不列出来了。各位读者有兴趣的话也可以去看看。
2025年02月19日
4 阅读
0 评论
0 点赞
2024-12-05
在wsl2中安装archlinux
在之前的博客中,我介绍了如何在虚拟机或者真实机上安装archlinux并且进行一定的配置,但是实际上Linux不管怎么配置在日常使用中都没有Windows简单便利,在开发有关Linux的程序时过去用虚拟机或者直接在Windows上使用ssh在远程服务器上进行开发。但是微软发布了wsl以及后续更新的wsl2,可以很方便的实现在Windows中拥有两个系统,并且两个系统可以进行互联。在不改变Windows操作习惯的基础之上操作Linux。进一步提升了Linux的便捷易用性。晚上的教程大多数都是使用wsl安装Ubuntu的,作为一个铁archlinux党,我不太用得惯Ubuntu,那么就要想办法安装自己习惯的arch,好在在网上有现成的教程。终于完成了这一工作准备工作安装wsl2,需要Windows 11或者Windows 10 的19041 及更高版本。因此如果系统版本不够需要提前进行系统的更新操作我们需要在Windows功能中开启 "适用于Linux的Windows子系统",如下图所示勾选之后可能需要重启。或者也可以在应用商店进行安装。这里就不得不吐槽一下微软的应用商店了,它居然能做到挂梯子和不挂梯子一样卡。我这里死活登录不上,就不演示这种方式了安装完成之后可以在powershell中查看它的版本wsl -v从图上可以看到,我们已经安装上了wsl2安装 archlinux安装完wsl2 之后,我们可以在GitHub官网上下载最新的ArchWSL。这里我们要下载两个东西,一个是不带online 标识的appx文件以及同名的cer文件。下载完成之后双击 .cer 文件,点击“安装证书”,选择“本地计算机”,在下一个页面中选择“将所有的证书都放入下列存储”,点击“浏览”,选择“受信任的根证书颁发机构”,执行安装。证书安装完成之后,我们双击下载的appx 文件,直接点击安装appx文件安装完成之后,可以使用wsl --list来查看当前wsl中的Linux子系统此时已经有了对应的系统了我们在命令行输入 arch 即可进入archlinux子系统,此时是以root的身份进入的配置arch配置普通用户新系统安装之后的第一件事就是创建一个普通用户,并且永远以这个普通用户进行登录,在需要的时候使用 sudo 来申请某些管理员权限进行操作我们在之前安装archlinux的教程中已经提到过对应的操作方式useradd -m -G wheel -s /bin/bash arch我们创建一个名为 arch 的用户,并指定shell为 bash接下来我们使用passwd arch passwd root来设置root和arch两个用户的密码。因为archlinux中安装的编辑器是vim,所以我们先将vim设置一个名为vi的别名ln -sf /usr/bin/vim /usr/bin/vi然后 使用visudo 将文件中 #%whell ALL=(ALL) ALL 这行的注释去掉,以便当前用户能够使用 sudo 命令接着可以使用su arch 将当前用户切换到arch。并且使用命令sudo pacman -Syyu来更新系统,同时测试一下输入用户密码之后能否执行一些root命令之后我们推出 arch 子系统,在powershell中执行Arch.exe config --default-user arch来指定默认使用arch 来登录系统设置完登录用户之后,在powershell中输入 arch 进入archlinux子系统中,此时我们发现,登录用户已经变成arch了初始化密钥环和更新源接着我们执行以下命令,来初始化密钥环sudo pacman-key --init sudo pacman-key --populate sudo pacman -Syy archlinux-keyring sudo pacman -Su鉴于目前国内的网络环境,上述几条命令有可能执行出问题或者卡着不动,我们可以进行换源的操作,这里我采用清华源在/etc/pacman.d/mirrorlist 文件的最顶端添加Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch开启32位软件库支持与ArchLinuxCN库的支持按照之前博客中的内容,我们先打开 32位软件的支持,在 /etc/pacman.conf 中去掉[multilib]一节中两行的注释,来开启 32 位库支持。然后在该文件的结尾处加入下面的文字,来开启 ArchLinuxCN 源[archlinuxcn] Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch之后通过以下命令安装 archlinuxcn-keyring 包导入 GPG key。pacman -Sy archlinuxcn-keyring具体的使用可以看镜像的官方文档如果报错可以看官网或者看我博客的办法是否能解决上述命令都成功之后使用 sudo pacman -S yay 来安装 yay成功之后我们可以试着安装一下neofetchyay -S neofetch安装成功之后,执行neofetch 就可以看到系统信息了配置终端基础内容安装完成之后,我们可以对终端进行一下美化和配置,毕竟日常使用上大部分时间都是直接在终端中使用,有一个漂亮点的终端用起来也舒服一点我们首先安装一下必要的组件sudo pacman -S net-tools man-db man-pages man-pages-zh_cn texinfo ntfs-3g tree pacman-contrib neofetch wget git usbutils pciutils acpi base-devel接着我们安装一下相应的字体sudo pacman -S adobe-source-han-serif-cn-fonts wqy-zenhei sudo pacman -S noto-fonts-cjk noto-fonts-emoji noto-fonts-extra ## 这里我把官方推荐的所有带unicode标识的全装上了,这样后续就不太会出现乱码的情况了 yay -S ttf-ubraille ttf-symbola otf-cm-unicode ttf-arphic-ukai ttf-arphic-uming ttf-dejavu gnu-free-fonts ttf-google-fonts-git nerd-fonts-complete ttf-hack ttf-joypixels默认的bash 功能比较弱,我们采用zshsudo pacman -S zsh然后将默认的shell 设置为 zshchsh -l # 列出系统中存在的所有shell chsh -s /bin/zsh #根据上一个命令得到的shell路径,设置当前shell我们推出系统再次登录的时候,shell已经切换到zsh了,我们按照提示生成一个默认的 .zshrc 文件即可为了支持终端上显示一些图形,我们需要安装 nerd-font 。可以在GitHub上找到 nerd-font可以通过git clone https://github.com/ryanoasis/nerd-fonts.git --depth=1来克隆,也可以通过在宿主机上下载zip包,然后传入archlinux 中。我们可以直接在Windows的文件资源管理器上输入 \\wsl$ 来访问archlinux的文件系统在获取项目之后,在项目的根目录执行 sh ./install.sh 来执行安装需要注意的是,如果你是通过本地的windows terminal 来ssh到远程archlinux化,本地也需要安装 nerd-font 因为这个时候显示的责任在宿主机的终端程序。需要宿主机本身也有那些字体。Windows上可以使用 .\install.ps1 来安装字体准备好后,我们可以使用 powerlevel10k 来美化终端git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ~/powerlevel10k echo 'source ~/powerlevel10k/powerlevel10k.zsh-theme' >>~/.zshrc source ~/.zshrc接着按照它的提示选择样式即可,如果不满意了,可以在 .zshrc 中对应的配置,直接重新选择样式即可。完成之后,可以看到终端相对来说比较好看了接下来我们对zsh 进行一些简单的配置安装 zsh-autosuggestions ,它是一个命令提示插件,当你输入命令时,会自动推测你可能需要输入的命令,按下右键可以快速采用建议git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions在 .zshrc 中添加下列代码source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh安装完成之后效果如下我们可以按TAB自动补全[zsh-syntax-highlighting]() 是一个命令语法校验插件,在输入命令的过程中,若指令不合法,则指令显示为红色,若指令合法就会显示为绿色。git clone https://github.com/zsh-users/zsh-syntax-highlighting.git echo "source ${(q-)PWD}/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" >> ${ZDOTDIR:-$HOME}/.zshrc安装完成之后效果如下autojump 是一个懒人神奇,有了它,当我们此前跳转过某个路径之后,可以很方便的跳转到之前路径。例如我们之前跳转到/usr/bin /home/arch那么我们可以直接使用 j b 跳转到 /usr/bin 中,或者在其他目录使用 j a 跳转到家目录中,如果跳转的目录路径有相似的字符,可能需要多输入一些字符来区分我们下面来安装它git clone https://github.com/wting/autojump.git cd autojump ./install.py安装好之后,它会提示我们需要手动将下列命令加入到 /zshrc 中,我们添加就好了thefuck 这也是一个懒人神奇,当命令输入错误的时候只要fuck一下就好了在archlinux中,我们可以直接使用sudo pacman -S thefuck我们将下列代码放入到 .zshrc 中eval $(thefuck --alias)安装完成之后,效果如下使用gui程序在Windows11和Windows 10 的内部版本在19045以上的时候,wsl本身就可以直接在打开Linux的gui程序。这里我们安装一个firefox作为测试例子sudo pacman -S firefox firefox-i18n-zh-cn我们启动firefox,这个时候报错了不要慌,这里我们需要链接wslg的接口套接字到x11sudo rm -r /tmp/.X11-unix ln -s /mnt/wslg/.X11-unix /tmp/.X11-unix可以将这段代码手动添加到 .zshrc 中,以便重启之后仍然能生效if ! [ -S /tmp/.X11-unix/X0 ]; then sudo ln -sf /mnt/wslg/.X11-unix/X0 /tmp/.X11-unix/X0 fi这个时候再打开就能在Windows上看到firefox的界面了还有一个惊喜,那就是我们可以从开始菜单中找到对应的Linux gui程序,并且直接点击就能打开。使用rdp连接除了这种使用方式,我们还可以使用rdp通过Windows的远程连接来进入archlinux子系统。这里我不太推荐这种方式,因为上面那种方式可以直接在Windows上使用linux gui程序,已经特别方便了,而且这种方式需要有桌面环境,需要消耗资源,但是当你的Windows版本不够的时候,可以考虑使用这种方式来使用gui程序这里我们先安装桌面环境sudo pacman -S xfce4 xfce4-goodies这里我采用轻量的xfce4,不管是使用kde 还是gnome,感觉都比较重接着我们下载rdp相关的软件yay -S xrdp xorgxrdp-glamor pulseaudio-module-xrdp根据 arch wiki 的说法,xrdp 仅支持使用XVNC作为后端,所以这里我们需要安装一下 vncsudo pacman -S tigervnc安装完成之后,需要在home目录下,添加一个.xinitrc 文件,这个文件会在rdp新建一个虚拟桌面的时候执行,文件的内容如下unset SESSION_MANAGER unset DBUS_SESSION_BUS_ADDRESS exec dbus-launch startxfce4最后我们启动一个rdp服务sudo systemctl start xrdp.service最后我们就可以使用Windows远程桌面连接上Linux的桌面了好了,配置到这里也就基本结束了,希望各位小伙伴在其中玩的愉快。总体来说Windows的wsl用起来还是很香的,特别是使用wslg服务在Windows中使用Linux的gui程序。它用起来就跟在Windows上开启一个gui程序一样丝滑,可以很好的将Linux程序融入到Windows的工作流中。
2024年12月05日
80 阅读
10 评论
0 点赞
2022-03-06
dwm 美化
在之前的博客中,我们将arch linux这个系统进行了一些美化,当然也是仅仅做到能看这个地步,要说跟网上其他那些惊艳的特效对比,肯定是不如的。但是我一直秉持一个观点,美化应该适可而止,只要不是丑的你不想打开,不想用,就已经足够了。所以我们不再对系统本身做其他美化,下面开始进行dwm本身的美化dwm美化相关插件安装上一篇博文中,为了解决从登陆管理器进入dwm无法加载背景图片的问题,我们已经安装了dwm的autostart插件,为了进一步的美化,这里再安装几个插件wget https://dwm.suckless.org/patches/alpha/dwm-alpha-20201019-61bb8b2.diff # 半透明 wget https://dwm.suckless.org/patches/barpadding/dwm-barpadding-20211020-a786211.diff #适当添加标题栏间距 wget https://dwm.suckless.org/patches/uselessgap/dwm-uselessgap-20211119-58414bee958f2.diff #dwm窗口间添加边距 使用patch 命令之后,重新编译安装。重启之后发现dwm已经变样了设置状态条根据dwm官方的说法,使用xsetroot -name 来设置标题栏的内容,比如说我们使用如下命令来打印当前用户xsetroot -name $(whoami)运行之后发现dwm的右上角显示的内容变了知道原理之后我们只需要在dwm启动的时候执行相关脚本,获取相关数据并刷新即可,例如可以使用如下命令实现每秒刷新时间while true do xsetroot -name "$(date)" sleep 1s done根据这个我们可以写一些脚本,获取各个状态,然后使用 xsetroot -name 来输出这些状态。但是这里我并不打算完全使用脚本来定义输出,而是使用dwmblocks来管理这个状态栏,输出各种状态。git clone https://github.com/torrinfail/dwmblocks.git进到对应目录中,编译并安装它make sudo make clean install安装完成之后我们在autostart 脚本末尾添加一行代码中启动dwmblocks程序dwmblocks &重启dwm之后可以看到变化,原来输出的日期变为了内存使用情况加日期的显示了进入到dwmblocks的目录中,会发现一个blocks.def.h和blocks.h的文件,这里我们删掉前一个文件,后续想要修改显示内容可以修改blocks.h文件//Modify this file to change what commands output to your statusbar, and recompile using the make command. static const Block blocks[] = { /*Icon*/ /*Command*/ /*Update Interval*/ /*Update Signal*/ {"Mem:", "free -h | awk '/^Mem/ { print $3\"/\"$2 }' | sed s/i//g", 30, 0}, {"", "date '+%b %d (%a) %I:%M%p'", 5, 0}, }; //sets delimeter between status commands. NULL character ('\0') means no delimeter. static char delim[] = " | "; static unsigned int delimLen = 5;其中blocks 数组是用来保存要获取的状态,每组状态用一个数组成员,其中每个成员又是一个字符串数组,每个部分分别代表了:状态前显示的图标,获取状态的命令,状态刷新的时间,更新的标志; 变量delim 表示各个状态之间的分割符这样我们可以讲获取状态和显示状态分离开来,实现模块化,后续可以将不同状态组织成不同模块,便于管理脚本这里我们计划输出网速、内存使用占比、cpu使用占比、音量、电量、亮度、时间这里我在dwmblocks 源码目录中创建一个scripts的目录用来存储获取这些状态的脚本,分别命名为: wlan.sh、memory.sh、cpu.sh、volume.sh、power.sh、light.sh、clock.sh然后修改blocks变量,通过调用这些脚本获取状态//Modify this file to change what commands output to your statusbar, and recompile using the make command. static const Block blocks[] = { /*Icon*/ /*Command*/ /*Update Interval*/ /*Update Signal*/ {" ", "~/scripts/wlan.sh", 1, 0}, //网速 {" ", "~/scripts/cpu.sh", 5, 0}, //cpu占用率 {" ", "~/scripts/memory.sh", 3, 0}, //内存占用率 {"", "~/scripts/volume.sh", 0, 11}, //音量 {"ﯦ ", "~/scripts/backlight.sh", 0, 11}, //亮度 {"", "~/scripts/battery.sh", 2, 0}, //电量 {"", "~/scripts/date.sh", 1, 0}, //时间 }; //sets delimeter between status commands. NULL character ('\0') means no delimeter. static char delim[] = " | "; static int delimLen = 5;接着在用户目录下新建一个scripts 目录,并新建这些脚本文件backlight.shxbacklight -get要使用xbacklight 这个工具需要事先安装acpilightsudo pacman -S acpilight sudo gpasswd video -a 用户名 # 将当前用户添加到video实现免root控制亮度 # 获取当前亮度 xbacklight -get # 设置亮度 xbacklight -set 70 # 增加亮度 xbacklight -inc 10 # 减少亮度 xbacklight -dec 10battery.sh#!/bin/bash get_battery_combined_percent() { total_charge=$(expr $(acpi -b | awk '{print $4}' | grep -Eo "[0-9]+" | paste -sd+ | bc)) battery_number=$(acpi -b | wc -l) percent=$(expr $total_charge / $battery_number) if [ "$percent" -le 33 ]; then if $(acpi -b | grep --quit Discharging); then printf " %s%%" "$percent" else printf " %s%%" "$percent" fi elif [ "$percent" -ge 33 ] && [ "$percent" -le 66 ]; then if $(acpi -b | grep --quit Discharging); then print " %s%%" "$percent" else printf " %s%%" "$percent" fi else if $(acpi -b | grep --quit Discharging); then printf " %s%%" "$percent" else printf " %s%%" "$percent" fi fi } get_battery_combined_percentcpu.sh#!/bin/sh # #脚本功能描述:依据/proc/stat文件获取并计算CPU使用率 # #CPU时间计算公式:CPU_TIME=user+system+nice+idle+iowait+irq+softirq #CPU使用率计算公式:cpu_usage=(idle2-idle1)/(cpu2-cpu1)*100 #默认时间间隔 TIME_INTERVAL=5 time=$(date "+%Y-%m-%d %H:%M:%S") LAST_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}') LAST_SYS_IDLE=$(echo $LAST_CPU_INFO | awk '{print $4}') LAST_TOTAL_CPU_T=$(echo $LAST_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}') sleep ${TIME_INTERVAL} NEXT_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}') NEXT_SYS_IDLE=$(echo $NEXT_CPU_INFO | awk '{print $4}') NEXT_TOTAL_CPU_T=$(echo $NEXT_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}') #系统空闲时间 SYSTEM_IDLE=`echo ${NEXT_SYS_IDLE} ${LAST_SYS_IDLE} | awk '{print $1-$2}'` #CPU总时间 TOTAL_TIME=`echo ${NEXT_TOTAL_CPU_T} ${LAST_TOTAL_CPU_T} | awk '{print $1-$2}'` CPU_USAGE=`echo ${SYSTEM_IDLE} ${TOTAL_TIME} | awk '{printf "%.2f", 100-$1/$2*100}'` echo "${CPU_USAGE}%"date.shdate '+ %Y年%m月%d日 %H:%M:%S'memory.shmemfree=$(($(grep -m1 'MemAvailable:' /proc/meminfo | awk '{print $2}'))) memtotal=$(($(grep -m1 'MemTotal:' /proc/meminfo | awk '{print $2}'))) useage=$(echo "scale=2;100 * ($memfree/$memtotal)" | bc) echo -e "$useage%"volume.sh#!/bin/bash VOL=$(amixer get Master | tail -n1 | sed -r "s/.*\[(.*)%\].*/\1/") if [ "$VOL" -eq 0 ]; then printf "ﱝ " elif [ "$VOL" -gt 0 ] && [ "$VOL" -le 33 ]; then print " %s%%" "$VOL" elif [ "$VOL" -gt 33 ] && [ "$VOL" -le 66 ]; then print "墳 %s%%" "$VOL" else print " %s%%" "$VOL" fiwlan.sh#!/bin/zsh function get_bytes { interface=$(ip route get 8.8.8.8 2>/dev/null | awk '{print $5}') line=$(grep $interface /proc/net/dev | cut -d ':' -f2 | awk '{print "received_bytes="$1, "transmitted_bytes="$9}') eval $line now=$(date +%s%N) } function get_velocity { value=$1 old_value=$2 now=$3 timediff=$(($now - $old_time)) velKB=$(echo "1000000000*($value-$old_value)/1024/$timediff" | bc) if test "$velKB" -gt 1024 then echo $(echo "scale=2; $velKB/1024" |bc)MB/s else echo ${velKB}KB/s fi } get_bytes old_received_bytes=$received_bytes old_transmitted_bytes=$transmitted_bytes old_time=$now get_bytes vel_recv=$(get_velocity $received_bytes $old_received_bytes $now) vel_trans=$(get_velocity $transmitted_bytes $old_transmitted_bytes $now) echo "$vel_recv⬇$vel_trans⬆"这些脚本主要取材自B站的UP主 TheCW ,脚本的地址如下:dwm status scripts也有部分参考了这个地址 dt scripts在上述脚本中有部分图标可能显示为乱码,这是因为读者本地没有安装对应的字体,这些图标都是我在nerd font 官网上找到的:Nerd Font Icons做完这些修改后重新编译dwmblocks 然后重启dwm就可以看到效果了dwm 其他部分修改这部分的修改主要在dwm目录的config.f1.修改左侧图标static const char *tags[] = { "", "", "", "", "", "ﱘ", ""};2.修改dwm配色static const char col_gray1[] = "#222222"; static const char col_gray2[] = "#444444"; static const char col_gray3[] = "#bbbbbb"; static const char col_gray4[] = "#ffffff"; static const char col_cyan[] = "#37374f";3.修改 窗口布局的图标static const Layout layouts[] = { /* symbol arrange function */ { "", tile }, /* first entry is default */ { "缾", NULL }, /* no layout function means floating behavior */ { "[M]", monocle }, };修改完成之后的样子如下针对终端和程序启动器的简单配置suckless 全家桶本身也有终端st和程序启动器dmenu,也是一贯以极简著称,但是我已经不想在过多的投入精力到这些的配置中了,这里我找到了一些开箱即用的程序作为st dmenu的替代瓶,等有精力和时间了再来折腾他们这里终端使用alacritty 程序启动器使用rofisudo pacman -S alacritty rofi可以在这里找到关于alacritty 的配色alacritty themes从 /usr/share/doc/alacritty/example/alacritty.yml 拷贝一份到~/.config/alacritty/alacritty.yml 作为配置文件,然后找到自己喜欢的配色,修改里面关于color的部分修改dwm中启动终端的快捷键static const char *termcmd[] = {"alacritty", NULL};关于rofi的主题,可以在这个网站中找到 rofi themegit clone --depth=1 https://github.com/adi1090x/rofi.git cd rofi ./setup.sh # 安装这里以misc里面的simple_kde 主题为例, 在~/.config/rofi/launcher/misc 中有launcher.sh ,找到最后一行rofi -no-lazy-grab -show drun -modi drun -theme $dir/"$theme"将这行写入dwm的配置文件中,修改最后的路径为对应的.rasi文件static const char *dmenucmd[] = { "rofi", "-no-lazy-grab","-show", "drun", "-modi", "drun", "-theme", "~/.config/rofi/launchers/misc/kde_simplemenu.rasi", NULL };最终的效果如下图当然还有一些其他的配置没有做,例如终端透明,标题栏也不算好看。比起一些网上大神的配置来,这些显得还是太朴素了,但是工具这种东西只要够用就行,实在不行还可以照抄其他觉得好的配置。我主要通过这段时间的折腾搞明白了如何从一个裸机一步步的搭建属于自己定制的初步可用的操作系统。以后使用别人的配置如果出现问题了也大概能知道如何处理。当然,我自己如今自己的机器也不是完全是这样,我主要使用的是YouTube上一个老外自己搞的一个DTOS,也是一个基于archlinux加其他工具配置起来的一个,对于工具我一项的主张是先找到别人好用的配置,然后根据自己的日常使用习惯进行修改,最后形成一套完全贴合自己的版本。在还不了解这个工具的情况从0开始配置一个是耗费时间,二是出现暂时无法解决的问题时会产生退却心理,第三个就是自己独立摸索出来的配置可能并不如一些大神配置的好用,最终可能会降低效率。
2022年03月06日
6 阅读
0 评论
0 点赞
2021-11-26
archlinux + dwm系统美化
上一次完成了dwm的基础安装和一些基本工具的安装,但是仍然只是基本的几个黑框框而已,与原来的tty终端来说没有什么大的改进,这里我就根据自己的配置来主要说说如何美化它,以及让它具备一个系统的基本功能。设置交换文件在桌面环境中,交换分区或文件用来实现休眠。即将当前环境保存在磁盘的交换文件或分区部分。除此之外,某些特定软件需要 swap 才可以正确运行。交换文件与分区性能相同,且交换文件更为灵活,可随时变更大小,增加与删除。dd if=/dev/zero of=/swapfile bs=1M count=16384 status=progress #创建16G的交换空间 大小根据需要自定 chmod 600 /swapfile #设置正确的权限 mkswap /swapfile #格式化swap文件 swapon /swapfile #启用swap文件最后,向 /etc/fstab中追加以下内容/swapfile none swap defaults 0 0设置背景图片编辑 .xinitr 文件,加入nitrogen和picom的配置,现在的.xinitrc 文件内容如下nitrogen --restore & # 保存并恢复上一次的配置 picom & exec dwm我们可以去一些网站下载一些高清的壁纸,然后在 dmenu中启动 nitrogen 设置壁纸点击 preferences 选择壁纸所在目录选择之后会出现里面的图片,选择一张作为壁纸关闭窗口之后就有壁纸了登陆管理器sddm安装使用pacman 安装sddm,并设置服务开机自启sudo pacman -S sddm sudo systemctl enable sddm接着创建启动项新建文件 /usr/share/xsessions/dwm.desktop, 中间如果某个目录没有,则创建它在dwm.desktop 中添加如下内容[Desktop Entry] Encoding=UTF-8 Name=Dwm Comment=Dynamic window manager Exec=dwm Icon=dwm Type=XSession重启之后就可以进入登陆界面了,输入用户和密码就可以进入系统,这个时候也可以看到直接就进入到dwm窗口了进入之后我们发现有一个问题,那就是之前设置的壁纸不会加载了,进入dwm之后是最初时候的黑色背景了。这是因为之前写在 .xinitrc 文件中的命令为执行的缘故,因为通过sddm进入系统是直接执行的dwm命令而不是通过 startx 在启动,因此通过这种方式进入系统之后,.xinitrc中的命令永远不会执行。这个问题可以通过dwm的补丁来解决。可以去官方网站下载auto-start 补丁wget https://dwm.suckless.org/patches/autostart/dwm-autostart-20210120-cb3f58a.diff patch < dwm-autostart-20210120-cb3f58a.diff sudo make clean install该补丁在dwm启动之后自动执行 ~/.dwm/autostart.sh 脚本中的内容,因此我们可以将以前在 .xinitrc 中的代码拷贝到该文件中mv dwm .dwm # 修改目录 touch autostart.sh #创建文件 chmod u+x autostart.sh # 给文件赋予执行权限 # 以下是文件中的内容 #!/usr/bin/zsh nitrogen --restore & picom --config ~/.config/picom.conf &有时候执行picom 会报错,说是无法启动 vsync 相关的功能,这种情况下可以拷贝一份配置文件到指定目录,修改文件, 将 vsync = true 改为 vsync = false, 关闭 vsync 的功能,autostart.sh 中关于picom 的配置,主要是为了制定使用修改后的配置文件主题定制与美化登陆界面到现在已经基本配置完成了,但是现在的界面并不好看,我希望将它做一些简单的没话,让它更符合自己的审美。我们可以去kde主题商店 去找。下载一个自己喜欢的主题,安装上它依赖的包(这个包可能根据主题的不同而不同,但大部分都会以来qt相关的一些组件)。下载下来之后,将整个目录拷贝到 /usr/share/sddm/theme中。后续主题所在目录的名称将作为主题名称进行配置可以通过命令 sddm-greeter --test-mode --theme /usr/share/sddm/themes/主题名 来预览一个主题预览没问题了之后可以通过配置文件来指定对应主题,sddm的默认配置文件位于/usr/lib/sddm/sddm.conf.d/default.conf 中,要修改配置,请在 /etc/sddm.conf.d 目录下创建配置文件,在这个目录中可以按照不同的小节放到不同的配置文件中,例如这里要配置主题,可以在这个目录下创建theme.conf, 并写下如下内容[Theme] Current= # 当前主题名称 CursorTheme= # 当前光标主题 DisableAvatarsThreshold=7 设置有多少个用户可以使用头像 EnableAvatars=true # 是否加载头像 FaceDir=/usr/share/sddm/faces # 头像所在目录 Font= #当前字体 Theme=/usr/share/sddm/themes #主题所在目录具体配置请参考 sddm.conf(5)grub 主题配置可以在 pling中下载喜欢的主题。解压并进入主题所在目录, 执行下列命令sudo cp -r . /usr/share/grub/themes/Nino # 拷贝主题文件接着编辑 /etc/default/grub 文件找到并修改 GRUB_THEME 项使其指向对应主题目录中的 theme.txt 文件GRUB_THEME=/usr/share/grub/themes/Nino/Miku/theme.txt在终端输入sudo grub-mkconfig -o /boot/grub/grub.cfg接着重启就可以看到新设置的主题了至此已经初步完成了进入系统之前的美化操作,接下来后面将要针对dwm以及st和dmenu进行改造,使其更加贴近日常使用
2021年11月26日
6 阅读
0 评论
0 点赞
2021-10-23
窗口管理器 dwm安装
上一篇博文中,已经完成了archlinux的安装,但是进去仅仅是一个冰冷冷的交互式命令窗口。没有图像,也无法打开浏览器。离日常使用还差的很远,接下来首先需要做的就是安装桌面环境。这里我不打算使用诸如gnome或者kde之类的桌面环境,一来这些桌面环境会自动帮我们把所有的给配置好,这不符合深度定制或者说折腾的本意,而来它们的体量相对来说还是比较大的,我想实现最小化安装,这里只需要一个窗口管理器就够了桌面环境与窗口管理器简述要将它作为日常使用来说,需要一个图形化的操作界面,与Windows不同的是,Linux自身并不包含图形操作界面,需要额外安装,而Windows是将图形操作界面作为内核的一部分。为了完成图形化的安装,可以使用桌面环境或者窗口管理器。桌面环境桌面环境结合X客户端,提供通用图形用户界面元素,如图标、工具栏、壁纸,桌面小部件。 大多数桌面环境包括提供一套整合的应用程序和实用工具。桌面环境包含了自己的一套窗口管理器,但是这个可以被替换。为了维持我们进行折腾的目的,这里采用仅仅安装窗口管理器的方式,后面陆续针对它仅配置,以达到和桌面环境差不多的效果安装前的准备工作在安装前需要做一些额外的工作,先下载安装好一些必备组件。sudo pacman -S net-tools man-db man-pages man-pages-zh_cn texinfo ntfs-3g tree pacman-contrib neofetch wget git usbutils pciutils acpinet-tools: 一个包含各种网络工具的库,像 ifconfig 或者 netstat,官方目前使用ip address 命令来获取本机的IP地址,但是我仍然喜欢使用ifconfg所以这里我安装上这个包man-db: 提供man命令man-pages: 提供man页面内容man-pages-zh_cn: 提供man中文页面內容,这个包下载下來不能直接用,后面改別名会提到texinfo: info帮助文档的包ntfs-3g: 对NTFS文件系統提供支持tree: 以树形结构显示目录中各种文件的依附关系pacman-contrib: pacman包管理器的扩展好像是,我主要用裡面的那个pactree命令neofetch: 一个显示系统信息的工具wget: 一个用來下载的工具git: 这个就不用说了,做程序员的都知道这个usbutils: 查看系统USB设备pciutils: 查看系统PCI设备acpi: 用來查看电池电量的工具一些基础工具安装好后,下面来安装中文和其他语言的字体包,防止后续出现乱码的情况sudo pacman -S adobe-source-han-serif-cn-fonts wqy-zenhei sudo pacman -S noto-fonts-cjk noto-fonts-emoji noto-fonts-extra ## 这里我把官方推荐的所有带unicode标识的全装上了,这样后续就不太会出现乱码的情况了 yay -S ttf-ubraille ttf-symbola otf-cm-unicode ttf-arphic-ukai ttf-arphic-uming ttf-dejavu gnu-free-fonts ttf-google-fonts-git nerd-fonts-complete ttf-hack ttf-joypixels接着安装一下驱动sudo pacman -S alsa-utils sof-firmware alsa-ucm-conf xf86-video-intel mesa xf86-input-libinputalsa-utils:声卡驱动sof-firmware:声卡驱动,如果你的机器比较新,那么你可能需要安裝。alsa-ucm-conf: 声卡驱动,如果你的机器比较新,那么你可能需要安裝。xf86-video-intel: Intel核显的渠道,这里我只安装了核心显卡的驱动,如果你有另外的独立显卡,请参考官方文档中的相关内容mesa: 用來配合显卡的另一种上层驱动xf86-input-libinput: 笔记本触摸板的驱动窗口管理器是搭载在x窗口系统之上的,安装窗口管理器之前需要先安装上x窗口系统的相关服务sudo pacman -S xorg xorg-xinit nitrogen picomxorg: x服务,用来显示图形界面xorg-init: x服务的启动程序nigrogen: 设置背景图片picom: 窗口渲染,后面做半透明渲染安装窗口管理器接下来就正式开始安装窗口管理器了,这里使用suckless全家桶,窗口管理器采用dwm, 程序启动器采用dmenu, 终端程序采用stgit clone https://git.suckless.org/dwm --depth=1 git clone https://git.suckless.org/st --depth=1 git clone https://git.suckless.org/dmenu --depth=1分别切换到这几个下载下来的目录中,依次执行 sudo make clean install 进行编译安装接着在用户的家目录下新建一个 .xinitrc 文件(ps: 也可以将 /etc/X11/xinit/xinitrc拷贝到家目录下并改名为.xinitrc,但是这个文件里面内容太多了,显的有点乱,所以我直接新建一个自己往里面加想要的内容)在文件中添加一行exec dwm保存退出后,输入命令 startx 即可看到dwm的窗口了dwm 基本用法dwm中最重要的键是 Mod1 键,这个键默认映射到了 Alt 键,使用 Mod1 + p 可以启动 dmenu, 然后只需要在上边出现的工具条中输入你想运行的程序的前几个字母,也可以按左右箭头在进行选择,按回车键完成,即可启动想要的程序可以使用 Shift + Mod1 + x 来将当前的活动窗口移到其他的标签页,其中x是标签页的编号关闭当前窗口可以使用 Mod1 + Shift +c 可以使用 Mod1 + Shift + q 来退出 dwm到现在已经完成了dwm的基本安装以及使用,但是它看起来是那样的不起眼,比起刚开始来说仅仅是多了几个可以运行的终端而已,后面将会介绍如何对它进行美化和相应的改造,让它变得漂亮起来
2021年10月23日
9 阅读
0 评论
0 点赞
2021-10-16
arch linux 安装
好长时间都没有更新自己的博客了,我简单翻阅了一下自己的更新记录,上一次更新好像还是在5月份左右,距今也有快半年,这半年也是遇到了很多事情,有不好的,也有好的。这半年我对在日常生活工作中使用Linux系统产生了一些兴趣,从零开始折腾这一系列的内容,主要从安装、配置、以及尝试各种软件来取代Windows的主导地位,也产生了一些心得,这里我想分几篇博客来聊聊我是如何慢慢使用arch Linux 来替代以前的Windows机器为何选择arch Linux我本身有一台6年前买的联想的笔记本,随着每次系统的更新,也变得越来越卡了,终于有一点我忍不了想着要不退回到windows 7吧,windows 10这台机器已经有点不行了。恰巧我最近在看一本关于计算机发展史的书,书中提到自由软件运动,那种运动有一种人人为我,我为人人的理想主义色彩,我想既然不能编写自由软件造福一方,至少应该享受自由软件带来的好处,而且国内经常爆出各种软件窃取用户隐私的新闻。何不趁此机会转移到自由软件阵营呢?说做就做,自由软件的基础自然是需要一个自由的操作系统,Linux是目前使用最为广泛的自由操作系统。在看了各种Linux发行版本之后我决定使用arch Linux,主要有以下几个原因:更新方式比较激进,arch Linux采用滚动更新的方式,这意味着用户能享受最新的软件版本,当然过激的更新行为会导致一些问题,比如常见的滚挂。我自认为我不缺少动手能力,这个我有信心能自己解决arch Linux 丰富的软件源使它能够安装其他发行版Linux无法安装的软件丰富的wiki文档,你能遇到的问题几乎都可以在里面找到答案最小化安装,arch Linux自身是最精简的系统,几乎精简到不能再精简。因此比起其他发行版本的Linux来说,它提供更高自由度的可配置性。安装困难,我一直觉得对于自己专业内的事情,要做就做最困难的,既然它的安装使用最为困难,那我就用它,当彻底征服了这一块内容,带来的成就感是无法比拟的。而且熟悉了它的安装过程,又例如提高对Linux的认识基于上述几点理由,我开始了漫长的折腾之路arch Linux 安装安装主要参考 arch wiki) 好在文档大部分都有中文版本,对于英语不好的人来说阅读起来也不会有过多的阻碍制作U盘启动项首先去官方指定的镜像站下载安装包,然后使用相应的工作制作U盘启动项,windows上我使用的是rufus、Linux或者mac上直接使用如下命令写入到U盘sudo dd bs=4M if=/path/to/archlinux.iso of=/dev/sdx status=progress oflag=sync上述命令的含义是制作一个镜像文件,源文件内容保存在if参数所指定的位置,输出到 of 所指定的位置, status=progress 表示现实制作进度, oflag=sync表示以同步的方式写入,即所有数据写入完成命令结束,而不是刚写入就结束需要注意的是,sdx 是u盘在系统中的命名,一般插入U盘后,在shell上使用fdisk -l可以看到,另外有的U盘可能经过分区,显示出下面还有sdx1、sdx2等分区,要写到sdx,而不是sdx1或者sdx2将U盘插入待装机的电脑上,进入bios调整启动顺序和安全设施,如果使用uefi方式启动的话,需要调整启动方式为uefi only 而不是 legacy/csm接下来就可以启动电脑,进入arch Linux的安装界面了联网设置进入到安装界面的第一步需要连接上网络,这里使用 iwctl 进行网络连接配置iwctl #进入交互式命令行 device list # 列出设备名,比如无线网卡一般叫做 wlan0 station wlan0 scan #扫描Wi-Fi station wlan0 get-networks #列出扫描到的Wi-Fi名称,例如要连接到esi-0这个Wi-Fi station wlan0 connect esi-0 #尝试连接,这个时候需要输入密码成功后就连上互联网了,可以使用 ping archlinux.org 来试试网络是否成功连上更新系统时间后续在访问https之类的站点时会验证客户端和服务器的证书和时间的,有时候时间不统一,在访问时可能会报无效的证书之类的错误使用命令timedatectl set-ntp true更新之后可以使用 timedatectl status 检查服务状态磁盘分区与格式化根据arch wiki上的说法,采用uefi的启动方式时,至少需要一个boot或者efi 分区作为efi系统分区(大小不能小于280M)、一个根分区。这里假设硬盘大小为100G,我采用如下的分区方案efi 分区 /efi 1G根分区 / 40G用户主目录 /home 剩余全部空间,越大越好跟windows 做类比的话,根分区相当于c 盘,主要用来装系统相关的内容,用户分区相当于D盘或者其他盘,用来放用户数据,后续如果系统挂了,重装系统的话,不会破坏用户目录的内容,甚至如果用户目录在其他物理盘上,后面换机器了直接将这块盘挂载到其他机器上,数据直接就能用了首先将磁盘分区表转化为gpt类型lsblk #显示分区状况 parted /dev/sdx #执行parted命令, 进行磁盘类型变更 (parted)mktable #输入mktable 修改磁盘分区表类型 new disk label type? gpt #输入gpt,修改分区表为gpt类型 quit #最后退出parted交互式命令 接下来使用cfdisk 命令对磁盘进行分区cfdisk /dev/sdx #使用cfdisd对磁盘进行分区free space 表示未分区的部分,上下键用来选择区域,左右键用来选择操作先选择new新建分区,然后输入大小,最后回车,重复几次这个操作,按照之前定义的大小来完成分区记得完成之后,将选项调整到wirte 在退出前将分区写入到磁盘。完成之后使用fdisk -l 查看分区接下来格式化磁盘中的各个分区efi 分区格式化为 vfat 格式根分区和用户分区格式化为 ext4格式mkfs.ext4 /dev/sda2 mkfs.ext4 /dev/sda3 mkfs.vfat /dev/sda1接下来将磁盘挂在到当前系统的文件目录下,使磁盘能正常被系统访问到mount /dev/sda2 /mnt mkdir /mnt/efi mkdir /mnt/home mount /dev/sda1 /mnt/efi mount /dev/sda3 /mnt/home系统安装折腾了这么多东西,终于要开始正式安装系统了,arch linux提供了一个脚本用来自动安装系统内核pacstrap /mnt base base-devel linux linux-firmware这句命令可以帮助我们将系统所需要的包安装到/mnt 这个目录也就是磁盘上等待一段时间,安装就完成了,先别着急重启,还有一些内容需要安装pacstrap /mnt dhcpcd vim sudo networkmanager # dhcpcd networkmanager 是网络相关的软件包,后期缺少可以通过网络下载,联网软件没有的话只能白瞎 系统自身配置到这里基本已经完成了安装部分的工作了,接下来要进行的就是重启前的基本配置了生成磁盘分区的记录文件genfstab -U /mnt >> /mnt/etc/fstab生成之后可以使用cat或者 vim 之类的命令复查一下生成的是否有误接下来切换到新安装的系统上arch-chroot /mnt在新系统中先在/etc/hostname中设置主机名,在文件中输入你想要的主机名,例如叫 arch接下来在文件/etc/hosts中设置与其匹配的条目,可以加入以下内容127.0.0.1 localhost ::1 localhost 127.0.1.1 arch.localdomain arch接着设置时区,在/usr/localtime 下用 /usr 中合适的时区创建符号连接ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime将系统时间同步到硬件时间hwclock --systohc接下来进行本地化操作,程序如果需要本地化文件,都需要依赖 locale,它规定了地域、货币、时区日期的格式、字符排列方式和本地化标准。需要在这两个文件中设置 locale.gen 与 locale.conf编辑 /etc/locale.gen 然后去掉 en_US.UTF-8 UTF-8 和其他需要的地区前的注释,例如作为中文用户可以去掉 zh_CN.UTF-8 UTF-8 以显示中文编辑完成之后使用如下命令生成 localelocale-gen在/etc/locale.conf 文件中指定系统使用的语言,这里推荐使用英文,否则在出错的时候可能会出现中文乱码,不便与排错echo 'LANG=en_US.UTF-8' > /etc/locale.conf设置root 密码passwd root根据cpu的不同,安装对应的微码,以确保处理器能稳定运行pacman -S intel-ucode #intel pacman -S amd-ucode #amd安装引导程序为了能在机器加电之后正常找到Linux所在位置,需要安装引导程序,来引导操作系统的启动。pacman -S grub efibootmgr # 使用grub做引导程序,efibootmgr 是uefi方式启动需要的 grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=arch #将启动项取名为arch 启动类型为efi的64位系统 系统启动位置在 /efi 接下来可以稍微对启动配置做一些修改,编辑 `/etc/default/grub` 文件,去掉 `GRUB_CMDLINE_LINUX_DEFAULT` 一行中最后的 `quit` 参数,同时把`log level` 的数值从3改到5,这样是为了后续如果出现系统错误方便排查。同时加入 `nowatchdog` 参数,这样可以显著提升开关机速度修改完成之后生成grub所需的配置文件grub-mkconfig -o /boot/grub/grub.cfg这样就完成了安装exit umount -R /mnt reboot一切顺利的话,重启之后应该就能进入系统了。新系统基础配置网络配置之前我们下载了与网络相关的两个工具networkmanager和dhcpcd,用来管理网络和dhcp自动分配IP地址systemctl enable --now NetworkManager # 启动networmmanager服务 nmcli device wifi list # 查看Wi-Fi列表 nmcli device wifi connect ssid password password #连接Wi-Fi,ssid表示Wi-Fi名,后面一个password表示连接wifi的真实密码网络连接成功之后,使用pacman将系统更新到最新版本pacman -Syyu创建非root用户为了系统安全防止自己某天抽风不小心输入类似 rm -rf / 之类的危险命令,平时最好使用非root登陆。 对于系统操作使用sudo来提升权限useradd -m -G wheel -s /bin/bash arch创建一个名为arch的用户,将用户组归属到wheel中,同时创建用户目录, 并且指定shell使用bash接下来使用 passwd arch 来修改用户密码由于系统中并没有安装vi,所以默认会使用vi命令的一些命令都会失效。所以需要将 vi 链接到 vimln -sf /usr/bin/vim /usr/bin/vi使用visudo 将文件中 #%whell ALL=(ALL) ALL 这行的注释去掉使用su arch 将当前用户切换到arch。可以使用命令sudo pacman -Syyu来更新系统,同时测试一下输入用户密码之后能否执行一些root命令设置交换文件在桌面环境中,交换分区或文件用来实现休眠(hibernate)的功能,即将当前环境保存在磁盘的交换文件或分区部分。除此之外,某些特定软件需要 swap 才可以正确运行。交换文件与分区性能相同,且交换文件更为灵活,可随时变更大小,增加与删除dd if=/dev/zero of=swapfile bs=1M count=4096 status=progress #设置4G的交换分区,大小根据系统的实际内存来决定,一般最好略大于物理内存 chmod 600 /swapfile mkswap /swapfile # 格式化swap文件 swapon /swapfile # 启用swap文件最后往/etc/fstab中追加如下内容/swapfile none swap defaults 0 0开启32位软件库支持与ArchLinuxCN库的支持为了系统的稳定,官方关闭了32位软件以及aur软件库,但是仅仅只依靠官方源中的软件时不够用的,这里我们要打开这两个库vim /etc/pacman.conf去掉[multilib]一节中两行的注释,来开启 32 位库支持。在文档结尾处加入下面的文字,来开启 ArchLinuxCN 源。[archlinuxcn] Server = https://mirrors.ustc.edu.cn/archlinuxcn/$arch执行 sudo pacman -Syyu 更新pacman数据库然后需要安装 archlinuxcn-keyring 包以导入 GPG keysudo pacman -S arhclinuxcn-keyring有时候因为密钥环的问题,导致这一步安装报错,可以依次执行下面的命令sudo pacman -syyu sudo pacman -S haveged sudo pacman -Syu haveged sudo systemctl start haveged sudo systemctl enable haveged sudo rm -fr /etc/pacman.d/gnupg sudo pacman-key --init sudo pacman-key --populate archlinux sudo pacman-key --populate archlinuxcn然后再重新安装,即可解决问题最后安装 yay 用来下载archlinuxcn库中的软件结尾至此,已经完成了对系统的安装到基础配置,现在已经有了一个基本可用的操作系统了,但是目前系统仍然只有一个基本的黑框框,作为日常使用还远远不足,至少还需要一个桌面环境,后面的博文会陆续介绍我是如何安装并配置一个基本的桌面环境。最后到一个基本可用于日常生活和工作中的操作系统。
2021年10月16日
7 阅读
0 评论
0 点赞