一周文章导读:在线试用 Linux 系统;Shell实践;VFS;Makefile陷阱;Shell陷阱
Table of Contents
在线试用 200 多种 Linux 和 Unix 操作系统
可以买到 Linux 电脑的 10 个地方
编写Linux Shell脚本的最佳实践
详解 Linux 中的虚拟文件系统
Linux Makefile 中的陷阱
陷阱一:在定义变量的语句后面空格之后使用了‘#’注释符
陷阱二:ifeq语句的括号里面,不要随意使用空格
陷阱三:在mingw环境下使用路径时的陷阱
Shell 脚本编程陷阱
在线试用 200 多种 Linux 和 Unix 操作系统
https://distrotest.net/
可以买到 Linux 电脑的 10 个地方
https://mp.weixin.qq.com/s/ICDmF2pctmH50CSZeYXYRA
编写Linux Shell脚本的最佳实践
https://mp.weixin.qq.com/s/tx1lmp-jViAOhTUBMbOoMQ
详解 Linux 中的虚拟文件系统
https://mp.weixin.qq.com/s/LXuzmkAHEW-_6F44jBWmWw
虚拟文件系统是一种神奇的抽象,它使得 “一切皆文件” 哲学在 Linux 中成为了可能。
什么是文件系统?根据早期的 Linux 贡献者和作家 Robert Love 所说,“文件系统是一个遵循特定结构的数据的分层存储。” 不过,这种描述也同样适用于 VFAT(虚拟文件分配表Virtual File Allocation Table)、Git 和Cassandra(一种 NoSQL 数据库)。那么如何区别文件系统呢?
Linux 内核要求文件系统必须是实体,它还必须在持久对象上实现 open()
、read()
和 write()
方法,并且这些实体需要有与之关联的名字。从 面向对象编程 的角度来看,内核将通用文件系统视为一个抽象接口,这三大函数是“虚拟”的,没有默认定义。因此,内核的默认文件系统实现被称为虚拟文件系统(VFS)。
VFS 是著名的类 Unix 系统中 “一切皆文件” 概念的基础。让我们看一下它有多奇怪,上面的小小演示体现了字符设备 /dev/console
实际的工作。该图显示了一个在虚拟电传打字控制台(tty)上的交互式 Bash 会话。将一个字符串发送到虚拟控制台设备会使其显示在虚拟屏幕上。而 VFS 甚至还有其它更奇怪的属性。例如,它可以在其中寻址。
我们熟悉的文件系统如 ext4、NFS 和 /proc 都在名为 file_operations 的 C 语言数据结构中提供了三大函数的定义。此外,个别的文件系统会以熟悉的面向对象的方式扩展和覆盖了 VFS 功能。正如 Robert Love 指出的那样,VFS 的抽象使 Linux 用户可以轻松地将文件复制到(或复制自)外部操作系统或抽象实体(如管道),而无需担心其内部数据格式。在用户空间这一侧,通过系统调用,进程可以使用文件系统方法之一 read()
从文件复制到内核的数据结构中,然后使用另一种文件系统的方法 write()
输出数据。
属于 VFS 基本类型的函数定义本身可以在内核源代码的 fs/*.c 文件 中找到,而 fs/
的子目录中包含了特定的文件系统。内核还包含了类似文件系统的实体,例如 cgroup、/dev
和 tmpfs,在引导过程的早期需要它们,因此定义在内核的 init/
子目录中。请注意,cgroup、/dev
和 tmpfs 不会调用 file_operations
的三大函数,而是直接读取和写入内存。
下图大致说明了用户空间如何访问通常挂载在 Linux 系统上的各种类型文件系统。像管道、dmesg 和 POSIX 时钟这样的结构在此图中未显示,它们也实现了 struct file_operations
,而且其访问也要通过 VFS 层。
VFS 是个“垫片层”,位于系统调用和特定 file_operations
的实现(如 ext4 和 procfs)之间。然后,file_operations
函数可以与特定于设备的驱动程序或内存访问器进行通信。tmpfs、devtmpfs 和 cgroup 不使用 file_operations
而是直接访问内存。
VFS 的存在促进了代码重用,因为与文件系统相关的基本方法不需要由每种文件系统类型重新实现。代码重用是一种被广泛接受的软件工程最佳实践!唉,但是如果重用的代码引入了严重的错误,那么继承常用方法的所有实现都会受到影响。
除了 /tmp
之外,大多数 Linux 用户最熟悉的 VFS 是 /proc
和 /sys
。(/dev
依赖于共享内存,而没有 file_operations
结构)。为什么有两种呢?让我们来看看更多细节。
procfs 为用户空间提供了内核及其控制的进程的瞬时状态的快照。在 /proc
中,内核发布有关其提供的设施的信息,如中断、虚拟内存和调度程序。此外,/proc/sys
是存放可以通过 sysctl 命令配置的设置的地方,可供用户空间访问。单个进程的状态和统计信息在 /proc/<PID>
目录中报告。
Linux Makefile 中的陷阱
https://mp.weixin.qq.com/s/YXOLoQgcw1x_znNehReELA
陷阱一:在定义变量的语句后面空格之后使用了‘#’注释符
陷阱二:ifeq语句的括号里面,不要随意使用空格
陷阱三:在mingw环境下使用路径时的陷阱
Shell 脚本编程陷阱
https://mp.weixin.qq.com/s/j3teXOXcqzrwPQ85pAOdCw
Shell 脚本很棒,你可以非常轻松地写出有用的东西来。甚至像是下面这个傻瓜式的命令:
# 用含有 Go 的词汇起名字:$ grep -i ^go /usr/share/dict/* | cut -d: -f2 | sort -R | head -n1goldfish
如果用其他编程语言,就需要花费更多的脑力,用多行代码实现,比如用 Ruby 的话:
puts(Dir['/usr/share/dict/*-english'].map do |f|File.open(f).readlines.select { |l| l[0..1].downcase == 'go' }end.flatten.sample.chomp)
Ruby 版本的代码虽然不是那么长,也并不复杂。但是 shell 版是如此简单,我甚至不用实际测试就可以确保它是正确的。而 Ruby 版的我就没法确定它不会出错了,必须得测试一下。而且它要长一倍,看起来也更复杂。
这就是人们使用 Shell 脚本的原因,它简单却实用。下面是另一个例子:
curl https://nl.wikipedia.org/wiki/Lijst_van_Nederlandse_gemeenten |grep '^<li><a href=' |sed -r 's|<li><a href="/wiki/.+" title=".+">(.+)</a>.*</li>|\1|' |grep -Ev '(^Tabel van|^Lijst van|Nederland)'
这个脚本可以从维基百科上获取荷兰基层政权的列表。几年前我写了这个临时的脚本,用来快速生成一个数据库,到现在它仍然可以正常运行,当时写它并没有花费我多少精力。但要用 Ruby 完成同样的功能则会麻烦得多。
现在来说说 shell 的缺点吧。随着代码量的增加,你的脚本会变得越来越难以维护,但你也不会想用别的语言重写一遍,因为你已经在这个 shell 版上花费了很多时间。
我把这种情况称为“Shell 脚本编程陷阱”,这是沉没成本谬论[1]的一种特例(LCTT 译注:“沉没成本谬论”是一个经济学概念,可以简单理解为,对已经投入的成本可能被浪费而念念不忘)。
实际上许多脚本会增长到超出预期的大小,你经常会花费过多的时间来“修复某个 bug”,或者“添加一个小功能”。如此循环往复,让人头大。
如果你从一开始就使用 Python、Ruby 或是其他类似的语言来写这个程序,你可能会在写第一版的时候多花些时间,但以后维护起来就容易很多,bug 也肯定会少很多。
以我的 packman.vim[2] 脚本为例。它起初只包含一个简单的用来遍历所有目录的 for 循环,外加一个 git pull,但在这之后就刹不住车了,它现在有 200 行左右的代码,这肯定不能算是最复杂的脚本,但假如我一上来就按计划用 Go 来编写它的话,那么增加一些像“打印状态”或者“从配置文件里克隆新的 git 库”这样的功能就会轻松很多;添加“并行克隆”的支持也几乎不算个事儿了,而在 shell 脚本里却很难实现(尽管不是不可能)。事后看来,我本可以节省时间,并且获得更好的结果。
出于类似的原因,我很后悔写出了许多这样的 shell 脚本,而我在 2018 年的新年誓言就是不要再犯类似的错误了。
需要指出的是,shell 编程的确存在一些实际的限制。下面是一些例子:
◈ 在处理一些包含“空格”或者其他“特殊”字符的文件名时,需要特别注意细节。绝大多数脚本都会犯错,即使是那些经验丰富的作者(比如我)编写的脚本,因为太容易写错了,只添加引号是不够的[3]。
◈ 有许多所谓“正确”和“错误”的做法。你应该用 which 还是 command?该用$@
还是 $*
,是不是得加引号?你是该用 cmd $arg 还是 cmd "$arg"?等等等等。
◈ 你没法在变量里存储空字节(0x00);shell 脚本处理二进制数据很麻烦。
◈ 虽然你可以非常快速地写出有用的东西,但实现更复杂的算法则要痛苦许多,即使用 ksh/zsh/bash 扩展也是如此。我上面那个解析 HTML 的脚本临时用用是可以的,但你真的不会想在生产环境中使用这种脚本。
◈ 很难写出跨平台的通用型 shell 脚本。/bin/sh
可能是 dash
或者 bash,不同的 shell 有不同的运行方式。外部工具如 grep、sed 等,不一定能支持同样的参数。你能确定你的脚本可以适用于 Linux、macOS 和 Windows 的所有版本吗(无论是过去、现在还是将来)?
◈ 调试 shell 脚本会很难,特别是你眼中的语法可能会很快变得记不清了,并不是所有人都熟悉 shell 编程的语境。
◈ 处理错误会很棘手(检查 $?
或是 set -e),排查一些超过“出了个小错”级别的复杂错误几乎是不可能的。
◈ 除非你使用了 set -u,变量未定义将不会报错,而这会导致一些“搞笑事件”,比如 rm -r ~/$undefined
会删除用户的整个家目录(瞅瞅 Github 上的这个悲剧[4])。
◈ 所有东西都是字符串。一些 shell 引入了数组,能用,但是语法非常丑陋和费解。带分数的数字运算仍然难以应付,并且依赖像 bc 或 dc
这样的外部工具($(( .. ))
这种方式只能对付一下整数)。
via: https://arp242.net/weblog/shell-scripting-trap.html
作者:Martin Tournoij[8] 选题:lujun9972 译者:jdh8383 校对:wxy
本文由 LCTT 原创编译,Linux中国 荣誉推出
一周文章导读:在线试用 Linux 系统;Shell实践;VFS;Makefile陷阱;Shell陷阱相关推荐
- linux是否有免安装程序,在线Ubuntu Linux系统,免安装体验Linux系统
如果你觉得安装Linux系统有困难,又或者你只想体验一下Linux系统是什么样的,有没有这样的好事?我可以肯定的回答你,有的,今天为你介绍在线Ubuntu Linux系统,你只需要点击Ubuntu在线 ...
- 《Linux内核分析》 第三周 构造一个简单的Linux系统MenuOS
Linux内核分析 第三周 构造一个简单的Linux系统MenuOS 张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/ ...
- ATTCK矩阵 linux系统安全实践
0×01 前言 MITRE在2013年推出了ATT&CK模型,根据真实的观察数据来描述和分类对抗行为.ATT&CK将已知攻击者行为转换为结构化列表,近两年来,也在安全行业中广受欢迎,涌 ...
- linux系统冒号模式map怎么用,shell中冒号 : 用途说明
我们知道,在Linux系统中,冒号(:)常用来做路径的分隔符(PATH),数据字段的分隔符(/etc/passwd)等.其实,冒号(:)在Bash中也是一个内建命令,它啥也不做,是个空命令.只起到占一 ...
- linux系统没有硬盘分区,Linux系统入门学习:硬盘分区的陷阱及应对
之所以想到写这篇,是因为本人在折腾Linux系统的过程中,有多次掉入硬盘分区的陷阱的经历.最近几天,再一次掉入坑中,折腾了两天才从坑中爬出来.经过多方查询资料,终于弄明白了硬盘分区的一些概念.下面将其 ...
- winpe查看不到linux硬盘分区,Linux系统入门学习:硬盘分区的陷阱及应对
本人在折腾Linux系统的过程中,有多次掉入硬盘分区的陷阱的经历.最近几天,再一次掉入坑中,折腾了两天才从坑中爬出来.经过多方 之所以想到写这篇,是因为本人在折腾Linux系统的过程中,有多次掉入硬盘 ...
- 一周文章导读:架构图;服务器;CPU
Table of Contents 阿里巴巴的技术专家,是如何画好架构图的? 先厘清一些基础概念 1.什么是架构 2.什么是架构图 3.架构图的作用 4.架构图分类 怎样的架构图是好的架构图 服务器 ...
- 在线的LINUX系统
http://bellard.org/jslinux/ http://www.masswerk.at/jsuix/index.html
- 推荐几个在线的Linux系统
1.Unix Terminal Online 打开连接: 打开网址链接: http://www.tutorialspoint.com/unix_terminal_online.php . 此网站可使用 ...
最新文章
- XML和实体类之间相互转换(序列化和反序列化)
- codeforces gym-101741 Subsequence Sum Queries 分治+离线
- 让计算机等待的函数_第56p,装饰器,闭包函数的应用
- san分布式共享文件系统_基于SAN存储共享卷实现openstack高可用的方法与流程
- tomcat安装-tomcat8.5
- thrift编写服务端 客户端
- InitInstance函数
- [小说连载]张小庆,在路上(2)- 兰博和威震天
- 机器视觉中常用图像处理库都有哪些?
- 携手网易打造世界杯主题房 YUNIK HOTEL玩转兴趣社交新场景
- 干货~~牛人教你如何写好一篇高分SCI论文
- 华为策略路由,实现双线选路上网
- android人脸抠图,人脸框抠图如何实现
- 投影仪光源与亮度科普
- 大数据本科毕业论文应该怎么写?
- 楞严经悬镜 明• 憨山大师 ----读记
- 如何批量导入不同文件夹中的图片
- Python开发图形可视化界面程序(一)
- krpano 切换大场景 xml 问题
- 电路中的电流采样IC选型
热门文章
- Echarts地图详细镇区的划分_echarts乡镇地图,echarts地图街道-算法与数据结构文档
- ABI 大屏(示例布局)
- kotlin泛型类、泛型接口
- 步步为营-49-视图
- Ubuntu 16.04 Steam
- CentOS 6 下升级安装Mysql 5.5 完整步骤
- 转载: .net程序员偏向XML开发的面试题
- hdb interface驱动是什么_Linux USB 鼠标驱动程序详解
- linux 重启服务器_linux入门-----6
- python mvc框架_MVC其实很简单(Django框架)