标签 Bash 下的文章

本周的《代码英雄》播客深入研究了最广泛使用的、已经成为事实标准的脚本语言,它来自于自由软件基金会及其作者的早期灵感。

 title=

对于任何从事于系统管理员方面的人来说,Shell 脚本编程是一门必不可少的技能,而如今人们编写脚本的主要 shell 是 Bash。Bash 是几乎所有的 Linux 发行版和现代 MacOS 版本的默认配置,也很快就会成为 Windows 终端的原生部分。你可以说 Bash 无处不在。

那么它是如何做到这一点的呢?本周的《代码英雄》播客将通过询问编写那些代码的人来深入研究这个问题。

肇始于 Unix

像所有编程方面的东西一样,我们必须追溯到 Unix。shell 的简短历史是这样的:1971 年,Ken Thompson 发布了第一个 Unix shell:Thompson shell。但是,脚本用户所能做的存在严重限制,这意味着严重制约了自动化以及整个 IT 运营领域。

这个奇妙的研究概述了早期尝试脚本的挑战:

类似于它在 Multics 中的前身,这个 shell(/bin/sh)是一个在内核外执行的独立用户程序。诸如通配(参数扩展的模式匹配,例如 *.txt)之类的概念是在一个名为 glob 的单独的实用程序中实现的,就像用于计算条件表达式的 if 命令一样。这种分离使 shell 变得更小,才不到 900 行的 C 源代码。

shell 引入了紧凑的重定向(<>>>)和管道(|^)语法,它们已经存在于现代 shell 中。你还可以找到对调用顺序命令(;)和异步命令()的支持。

Thompson shell 缺少的是编写脚本的能力。它的唯一目的是作为一个交互式 shell(命令解释器)来调用命令和查看结果。

随着对终端使用的增长,对自动化的兴趣随之增长。

Bourne shell 前进一步

在 Thompson 发布 shell 六年后,1977 年,Stephen Bourne 发布了 Bourne shell,旨在解决Thompson shell 中的脚本限制。(Chet Ramey 是自 1990 年以来 Bash 语言的主要维护者,在这一集的《代码英雄》中讨论了它)。作为 Unix 系统的一部分,这是这个来自贝尔实验室的技术的自然演变。

Bourne 打算做什么不同的事情?研究员 M. Jones 很好地概述了它:

Bourne shell 有两个主要目标:作为命令解释器以交互方式执行操作系统的命令,和用于脚本编程(编写可通过 shell 调用的可重用脚本)。除了替换 Thompson shell,Bourne shell 还提供了几个优于其前辈的优势。Bourne 将控制流、循环和变量引入脚本,提供了更具功能性的语言来(以交互式和非交互式)与操作系统交互。该 shell 还允许你使用 shell 脚本作为过滤器,为处理信号提供集成支持,但它缺乏定义函数的能力。最后,它结合了我们今天使用的许多功能,包括命令替换(使用后引号)和 HERE 文档(以在脚本中嵌入保留的字符串文字)。

Bourne 在之前的一篇采访中这样描述它:

最初的 shell (编程语言)不是一种真正的语言;它是一种记录 —— 一种从文件中线性执行命令序列的方法,唯一的控制流的原语是 GOTO 到一个标签。Ken Thompson 所编写的这个最初的 shell 的这些限制非常重要。例如,你无法简单地将命令脚本用作过滤器,因为命令文件本身是标准输入。而在过滤器中,标准输入是你从父进程继承的,不是命令文件。

最初的 shell 很简单,但随着人们开始使用 Unix 进行应用程序开发和脚本编写,它就太有限了。它没有变量、它没有控制流,而且它的引用能力非常不足。

对于脚本编写者来说,这个新 shell 是一个巨大的进步,但前提是你可以使用它。

以自由软件来重新构思 Bourne Shell

在此之前,这个占主导地位的 shell 是由贝尔实验室拥有和管理的专有软件。幸运的话,你的大学可能有权访问 Unix shell。但这种限制性访问远非自由软件基金会(FSF)想要实现的世界。

Richard Stallman 和一群志同道合的开发人员那时正在编写所有的 Unix 功能,其带有可以在 GNU 许可证下免费获得的许可。其中一个开发人员的任务是制作一个 shell,那位开发人员是 Brian Fox。他对他的任务的讲述十分吸引我。正如他在播客上所说:

它之所以如此具有挑战性,是因为我们必须忠实地模仿 Bourne shell 的所有行为,同时允许扩展它以使其成为一个供人们使用的更好工具。

而那时也恰逢人们在讨论 shell 标准是什么的时候。在这一历史背景和将来的竞争前景下,流行的 Bourne shell 被重新构想,并再次重生。

重新打造 Bourne Shell

自由软件的使命和竞争这两个催化剂使重制的 Bourne shell(Bash)具有了生命。和之前不同的是,Fox 并没有把 shell 放到自己的名字之后命名,他专注于从 Unix 到自由软件的演变。(虽然 Fox Shell 这个名字看起来要比 Fish shell 更适合作为 fsh 命令 #missedopportunity)。这个命名选择似乎符合他的个性。正如 Fox 在剧集中所说,他甚至对个人的荣耀也不感兴趣;他只是试图帮助编程文化发展。然而,他并不是一个优秀的双关语。

而 Bourne 也并没有因为他命名 shell 的文字游戏而感到被轻视。Bourne 讲述了一个故事,有人走到他面前,并在会议上给了他一件 Bash T 恤,而那个人是 Brian Fox。

Shell发布于创造者
Thompson Shell1971Ken Thompson
Bourne Shell1977Stephen Bourne
Bourne-Again Shell1989Brian Fox

随着时间的推移,Bash 逐渐成长。其他工程师开始使用它并对其设计进行改进。事实上,多年后,Fox 坚定地认为学会放弃控制 Bash 是他一生中最重要的事情之一。随着 Unix 让位于 Linux 和开源软件运动,Bash 成为开源世界的至关重要的脚本语言。这个伟大的项目似乎超出了单一一个人的愿景范围。

我们能从 shell 中学到什么?

shell 是一项技术,它是笔记本电脑日常使用中的一个组成部分,你很容易忘记它也需要发明出来。从 Thompson 到 Bourne 再到 Bash,shell 的故事为我们描绘了一些熟悉的结论:

  • 有动力的人可以在正确的使命中取得重大进展。
  • 我们今天所依赖的大部分内容都建立在我们行业中仍然活着的那些传奇人物打下的基础之上。
  • 能够生存下来的软件超越了其原始创作者的愿景。 代码英雄在全部的第三季中讲述了编程语言,并且正在接近它的尾声。请务必订阅,来了解你想知道的有关编程语言起源的各种内容,我很乐意在下面的评论中听到你的 shell 故事。

via: https://opensource.com/19/9/command-line-heroes-bash

作者:Matthew Broberg 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

两种编程语言都各有优缺点,它们在某些任务方面互有胜负。

BashPython 是大多数自动化工程师最喜欢的编程语言。它们都各有优缺点,有时很难选择应该使用哪一个。所以,最诚实的答案是:这取决于任务、范围、背景和任务的复杂性。

让我们来比较一下这两种语言,以便更好地理解它们各自的优点。

Bash

  • 是一种 Linux/Unix shell 命令语言
  • 非常适合编写使用命令行界面(CLI)实用程序的 shell 脚本,利用一个命令的输出传递给另一个命令(管道),以及执行简单的任务(可以多达 100 行代码)
  • 可以按原样使用命令行命令和实用程序
  • 启动时间比 Python 快,但执行时性能差
  • Windows 中默认没有安装。你的脚本可能不会兼容多个操作系统,但是 Bash 是大多数 Linux/Unix 系统的默认 shell
  • 与其它 shell (如 csh、zsh、fish) 完全兼容。
  • 通过管道(|)传递 CLI 实用程序如 sedawkgrep 等会降低其性能
  • 缺少很多函数、对象、数据结构和多线程支持,这限制了它在复杂脚本或编程中的使用
  • 缺少良好的调试工具和实用程序

Python

  • 是一种面对对象编程语言(OOP),因此它比 Bash 更加通用
  • 几乎可以用于任何任务
  • 适用于大多数操作系统,默认情况下它在大多数 Unix/Linux 系统中都有安装
  • 与伪代码非常相似
  • 具有简单、清晰、易于学习和阅读的语法
  • 拥有大量的库、文档以及一个活跃的社区
  • 提供比 Bash 更友好的错误处理特性
  • 有比 Bash 更好的调试工具和实用程序,这使得它在开发涉及到很多行代码的复杂软件应用程序时是一种很棒的语言
  • 应用程序(或脚本)可能包含许多第三方依赖项,这些依赖项必须在执行前安装
  • 对于简单任务,需要编写比 Bash 更多的代码

我希望这些列表能够让你更好地了解该使用哪种语言以及在何时使用它。

你在日常工作中更多会使用哪种语言,Bash 还是 Python?请在评论中分享。


via: https://opensource.com/article/19/4/bash-vs-python

作者:Archit Modi (Red Hat) 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

邮件列表证实最近发布了 Bash-5.0。而且,令人兴奋的是它还有新的功能和变量。

如果你一直在使用 Bash 4.4.XX,那么你一定会喜欢 Bash 的第五个主要版本。

第五个版本侧重于新的 shell 变量和许多重大漏洞修复。它还引入了一些新功能,以及一些与 bash-4.4 不兼容的更改。

Bash logo

新功能怎么样?

在邮件列表解释了此版本中修复的 bug:

此版本修复了 bash-4.4 中的几个主要错误,并引入了几个新功能。最重要的 bug 修复是对 nameref 变量的解析以及通过模糊测试发现的许多潜在的内存越界错误。在为了符合 Posix 标准解释而不进行单词拆分的上下文中,对 $@$* 的展开做了许多改变,另外还有解决极端情况中 Posix 一致性的修改。

它还引入了一些新功能。根据其发布说明,最值得注意的新功能是几个新的 shell 变量:

BASH_ARGV0EPOCHSECONDSEPOCHREALTIME。内置命令 history 可以删除指定范围的条目,并能将负数理解为从历史末端开始的偏移量。有一个选项允许局部变量继承前一个范围内具有相同名称的变量的值。有一个新的 shell 选项,在启用它时,会导致 shell 只尝试一次扩展关联数组下标(这在算术表达式中使用时会出现问题)。globasciiranges 这个 shell 选项现在默认启用。可以在配置时默认关闭它。

Bash-4.4 和 Bash-5.0 之间有哪些变化?

其更新日志提到了不兼容的更改和所支持的 readline 版本历史记录。它是这么说的:

bash-4.4 和 bash-5.0 之间存在一些不兼容的变化。尽管我已经尽量最小化兼容性问题,但是对 nameref 变量解析的更改意味着对变量名引用的某些使用会有不同的行为。默认情况下,如果启用了扩展调试模式,shell 仅在启动时设置 BASH_ARGCBASH_ARGV。它被无条件地设置是一个疏忽,并且在脚本传递大量参数时会导致性能问题。

如果需要,可以将 Bash 链接到已安装的 Readline 库,而不是 lib/readline 中的私有版本。只有 readline-8.0 及更高版本能够提供 bash-5.0 所需的所有符号。早期版本的 Readline 库无法正常工作。

我相信一些添加的功能/变量非常有用。我最喜欢的一些是:

  • 有一个新的(默认情况下禁用,文档中没有说明)shell 选项,用于在运行时启用/禁用向 syslog 发送历史记录。
  • 正如文档一直所说的那样,除非 shell 处于调试模式,否则它不会在启动时自动设置 BASH_ARGCBASH_ARGV,但如果脚本在上层引用它们且没有启用调试模式,那么 shell 将动态创建它们。
  • 现在可以使用 -d start-end 删除指定范围的 history 条目。
  • 如果启用了作业控制的非交互式 shell 检测到前台作业因 SIGINT 而死亡,则其行为就像接收到 SIGINT 一样。
  • BASH_ARGV0:一个新变量,扩展为 $0,并在赋值时设置为 $0

要查看完整的更改和功能列表,请参阅邮件列表文章

总结

你可以使用下面的命令检查你当前的 Bash 版本:

bash --version

你很可能安装了 Bash 4.4。如果你想获得新版本,我建议等待你的发行版提供它。

你怎么看待 Bash-5.0 发布?你在使用其他 bash 的替代品么?如果有的话,这个更新会改变你的想法么?

请在下面的评论中告诉我们你的想法。


via: https://itsfoss.com/bash-5-release

作者:Ankush Das 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Paul Brown 解释了 Linux shell 命令中那个不起眼的“点”的各种意思和用法。

在现实情况中,使用 shell 命令编写的单行命令或脚本可能会令人很困惑。你使用的很多工具的名称与它们的实际功能相差甚远(grepteeawk,还有吗?),而当你将两个或更多个组合起来时,所组成的 “句子” 看起来更像某种外星人的天书。

因此,上面说的这些对于你并无帮助,因为你用来编写一连串的指令所使用的符号根据你使用的场景有着不同的意义。

位置、位置、位置

就拿这个不起眼的点(.)来说吧。当它放在一个需要一个目录名称的命令的参数处时,表示“当前目录”:

find . -name "*.jpg"

意思就是“在当前目录(包括子目录)中寻找以 .jpg 结尾的文件”。

ls .cd . 结果也如你想的那样,它们分别列举和“进入”到当前目录,虽然在这两种情况下这个点都是多余的。

而一个紧接着另一个的两个点呢,在同样的场景下(即当你的命令期望一个文件目录的时候)表示“当前目录的父目录”。如果你当前在 /home/your_directory 下并且运行:

cd ..

你就会进入到 /home。所以,你可能认为这仍然适合“点代表附近目录”的叙述,并且毫不复杂,对吧?

那下面这样会怎样呢?如果你在一个文件或目录的开头加上点,它表示这个文件或目录会被隐藏:

$ touch somedir/file01.txt somedir/file02.txt somedir/.secretfile.txt
$ ls -l somedir/
total 0
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 file01.txt
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 file02.txt
$ # 注意上面列举的文件中没有 .secretfile.txt
$ ls -la somedir/
total 8
drwxr-xr-x 2 paul paul 4096 Jan 13 19:57 .
drwx------ 48 paul paul 4096 Jan 13 19:57 ..
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 file01.txt
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 file02.txt
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 .secretfile.txt
$ # 这个 -a  选项告诉 ls 去展示“all”文件,包括那些隐藏的

然后就是你可以将 . 当作命令。是的,你听我说:. 是个真真正正的命令。它是 source 命令的代名词,所以你可以用它在当前 shell 中执行一个文件,而不是以某种其它的方式去运行一个脚本文件(这通常指的是 Bash 会产生一个新的 shell 去运行它)

很困惑?别担心 —— 试试这个:创建一个名为 myscript 的脚本,内容包含下面一行:

myvar="Hello"

然后通过常规的方法执行它,也就是用 sh myscript(或者通过 chmod a+x myscript 命令让它可执行,然后运行 ./myscript)。现在尝试并且观察 myvar 的内容,通过 echo $myvar(理所当然你什么也得不到)。那是因为,当你的脚本赋值 "Hello"myvar 时,它是在一个隔离的bash shell 实例中进行的。当脚本运行结束时,这个新产生的实例会消失并且将控制权转交给原来的shell,而原来的 shell 里甚至都不存在 myvar 变量。

然而,如果你这样运行 myscript

. myscript

echo $myvar 就会打印 Hello 到命令行上。

当你的 .bashrc 文件发生变化后,你经常会用到 .(或 source)命令,就像当你要扩展 PATH 变量那样。在你的当前 shell 实例中,你可以使用 . 来让变化立即生效。

双重麻烦

就像看似无关紧要的一个点有多个含义一样,两个点也是如此。除了指向当前目录的父级之外,两个点(..)也用于构建序列。

尝试下这个:

echo {1..10}

它会打印出从 1 到 10 的序列。在这种场景下,.. 表示 “从左边的值开始,计数到右边的值”。

现在试下这个:

echo {1..10..2}

你会得到 1 3 5 7 9..2 这部分命令告诉 Bash 输出这个序列,不过不是每个相差 1,而是相差 2。换句话说,就是你会得到从 1 到 10 之间的奇数。

它反着也仍然有效:

echo {10..1..2}

你也可以用多个 0 填充你的数字。这样:

echo {000..121..2}

会这样打印出从 0 到 121 之间的偶数(填充了前置 0):

000 002 004 006 ... 050 052 054 ... 116 118 120

不过这样的序列发生器有啥用呢?当然,假设您的新年决心之一是更加谨慎控制您的帐户花销。作为决心的一部分,您需要创建目录,以便对过去 10 年的数字发票进行分类:

mkdir {2009..2019}_Invoices

工作完成。

或者你可能有数百个带编号的文件,比如从视频剪辑中提取的帧,或许因为某种原因,你只想从第 43 帧到第 61 帧每隔三帧删除一帧:

rm frame_{043..61..3}

很可能,如果你有超过 100 个帧,它们将以填充 0 命名,如下所示:

frame_000 frame_001 frame_002 ...

那就是为什么你在命令中要用 043,而不是43 的原因。

花括号花招

说实话,序列的神奇之处不在于双点,而是花括号({})的巫术。看看它对于字母是如何工作的。这样做:

touch file_{a..z}.txt

它创建了从 file_a.txtfile_z.txt 的文件。

但是,你必须小心。使用像 {Z..a} 这样的序列将产生一大堆大写字母和小写字母之间的非字母、数字的字符(既不是数字或字母的字形)。其中一些字形是不可打印的或具有自己的特殊含义。使用它们来生成文件名称可能会导致一系列意外和可能令人不快的影响。

最后一件值得指出的事:包围在 {...} 的序列,它们也可以包含字符串列表:

touch {blahg,splurg,mmmf}_file.txt

将创建了 blahg_file.txtsplurg_file.txtmmmf_file.txt

当然,在别的场景中,大括号也有不同的含义(惊喜吗!)。不过那是别的文章的内容了。

总结

Bash 以及运行于其中的各种工具已经被寻求解决各种特定问题的系统管理员们把玩了数十年。要说这种有自己之道的系统管理员是一种特殊物种的话,那是有点轻描淡写。总而言之,与其他语言相反,Bash 的设计目标并不是为了用户友好、简单、甚至合乎逻辑。

但这并不意味着它不强大 —— 恰恰相反。Bash 的语法和 shell 工具可能不一致且很庞大,但它们也提供了一系列令人眼花缭乱的方法来完成您可能想象到的一切。就像有一个工具箱,你可以从中找到从电钻到勺子的所有东西,以及橡皮鸭、一卷胶带和一些指甲钳。

除了引人入胜之外,探明你可以直接在 shell 中达成的所有能力也很有趣,所以下次我们将深入探讨如何构建更大更好的 Bash 命令行。

在那之前,玩得开心!


via: https://www.linux.com/blog/learn/2019/1/linux-tools-meaning-dot

作者:Paul Brown 选题:lujun9972 译者:asche910 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

初学者可以在此教程中了解环境变量。

bash 变量,尤其是讨厌的环境变量,已经是一个老生常谈的话题了。我们也更应该对它有一个详细的了解,让它为我们所用。

下面就打开终端,开始吧。

环境变量

HOME (LCTT 译注:双关语)除了是你脱下帽子惬意休息的地方,同时也是 Linux 中的一个变量,它是当前用户主目录的路径:

echo $HOME

以上这个命令会显示当前用户的主目录路径,通常都在 /home/<your username> 下。

顾名思义,变量的值是可以根据上下文变化的。实际上,Linux 系统中每一个用户的 HOME 变量都是不一样的,当然你也可以这样自行更改 HOME 变量的值:

HOME=/home/<your username>/Documents

以上这个命令将会把 HOME 变量设置为你的 Documents 目录。

其中有三点需要留意:

  1. = 符号和其两侧的内容之间不加空格。空格在 shell 中有专门的意义,不能随意地在任何地方添加空格。
  2. 如果你需要对变量进行赋值,只需要使用变量名称就可以了。但如果需要读取或者使用变量的值,需要在变量前面加上一个 $ 号。
  3. 更改 HOME 变量具有一定的风险。有很多程序是依赖于 HOME 变量的,更改 HOME 变量可能会导致一些不可预见的结果。例如,如果按照上面的方式更改了 HOME 变量,然后执行不带有任何参数的 cd 命令,在通常情况下,会跳转到用户的主目录下,但在这个时候,会跳转到 HOME 变量指定的目录下。

上面第 3 点中环境变量的更改并不是持久有效的,在终端关闭后重新打开终端,又或者是新建一个终端,执行 echo $HOME 命令输出的仍然会是初始的值,而不是重新自定义的值。

在讨论如何持久地更改一个环境变量之前,我们先来看一下另一个比较重要的环境变量。

PATH 变量

PATH 变量中存放了一系列目录,而且是放置了可执行程序的目录。正是由于 PATH 变量的存在,让你不需要知道应用程序具体安装到了什么目录,而 shell 却可以正确地找到这些应用程序。

如果你查看 PATH 变量的值,大概会是以下这样:

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin

每两个目录之间使用冒号 : 分隔。如果某个应用程序的所在目录不在 PATH 变量中,那么运行的时候就需要声明应用程序的目录让 shell 能够找到。

/home/<user name>/bin/my_program.sh

例如以上命令就会执行当前用户 bin/ 目录下的 my_program.sh 文件。

有一个常见的问题:如果你不希望弄乱系统的 bin/ 目录,同时也不希望你自己的文件被其它人运行,还不想每次运行的时候都要输入完整的路径,那么,你可以在你的主目录中创建一个独立的 bin/ 目录:

mkdir $HOME/bin

然后将这个目录添加到 PATH 变量中:

PATH=$PATH:$HOME/bin

然后 /home/<user name>/bin/ 目录就会出现在 PATH 变量中了。但正如之前所说,这个变更只会在当前的 shell 生效,当前的 shell 一旦关闭,环境变量的值就又恢复原状了。

如果要让变更对当前用户持续生效,就不能在 shell 中直接执行对应的变更,而是应该将这些变更操作写在每次启动 shell 时都会运行的文件当中。这个文件就是当前用户主目录中的 .bashrc 文件。文件名前面的点号表明这是一个隐藏文件,执行普通的 ls 命令是不会将这个文件显示出来的,但只要在 ls 命令中加入 -a 参数就可以看到这个文件了。

你可以使用诸如 kategeditnano 或者 vim 这些文本编辑器来打开 .bashrc 文件(但不要用 LibreOffice Writer,它是一个文字处理软件,跟前面几个文字编辑器完全不同)。打开 .bashrc 文件之后,你会看见里面放置了一些 shell 命令,是用于为当前用户设置环境的。

在文件的末尾添加新行并输入以下内容:

export PATH=$PATH:$HOME/bin

保存并关闭 .bashrc 文件,接下来你就会看到 export 语句的效果。执行以下的命令让刚才的修改立即生效:

source .bashrc

刚才执行的 source 命令让 .bashrc 文件在当前的 shell 立即生效,并且对于之后打开的 shell 都会有效。因此另一个等效的方法是退出并重新进入 shell,但这样也太麻烦了。

现在,你的 shell 就能自动寻找到 /home/<user name>/bin/ 下的程序了,执行这个目录下的程序也不需要完整地写出程序的路径。

自定义变量

当然,你也可以定义自己的变量。刚才我们看到的变量名称都是全大写的,实际上变量名称的定义还是比较灵活的

定义新变量的过程非常直观,直接对它赋值就可以了:

new_variable="Hello"

然后可以用以下的方式读取到已定义变量的值:

echo $new_variable

程序的正常工作离不开各种变量,例如要将某个选项设置为打开,又或者让程序找到所需的代码库,都需要使用变量。在 bash 中运行程序的时候会生成一个子 shell,这个子 shell 和执行原程序的父 shell 并不是完全一样的,只是继承了父 shell 的部分内容,而且默认是不继承父 shell 中的变量的。因为变量默认情况下是局部变量,出于安全原因,一个 shell 中的局部变量不会被另一个 shell 读取到,即使是子 shell 也不可以。

下面举一个例子。首先定义一个变量:

robots="R2D2 & C3PO"

然后执行:

bash

现在是在 bash shell 中创建了一个子 shell。

执行这个命令看看还能不能读取到刚才定义的变量:

echo $robots

你会发现读取不到。

还是在这个子 shell 中,为 robots 变量赋一个不同的值:

robots="These aren't the ones you are looking for"

再读取一次:

$ echo $robots
These aren't the ones you are looking for

退出这个子 shell:

exit

然后再看一下现在 robots 变量的值:

$ echo $robots
R2D2 & C3P0

这一个特性可以有效避免配置过程中产生混乱,同时也会导致一个问题:如果程序中需要设置变量,但却由于子 shell 的原因无法正常访问到这个变量,该如何解决呢?这个时候就需要用到 export 了。

重复一次刚才的过程,但这一次不是通过 robots="R2D2 & C3PO" 方式来设置变量,而是使用 export 命令:

export robots="R2D2 & C3PO"

现在你会发现,在进入子 shell 之后,robots 变量的值仍然是最初赋予的值。

要注意的是,尽管子 shell 会继承通过 export 导出的变量,但如果在子 shell 中对这个变量重新赋值,是不会影响到父 shell 中对应变量的。

如果要查看所有通过 export 导出的变量,可以执行以下命令:

export -p

自定义的变量会显示在这个列表的末尾。这个列表中还有一些常见的变量:例如 USER 的值是当前用户的用户名,PWD 的值是当前用户当前所在的目录,而 OLDPWD 的值则是当前用户上一个访问过的目录。因此如果执行:

cd -

就会切换到上一个访问过的目录,那是因为 cd 命令读取到了 OLDPWD 变量的值。

你也可以使用 env 命令查看所有环境变量。

如果要取消导出一个变量,可以加上 -n 参数:

export -n robots

接下来

了解过环境变量的知识之后,你已经到达了可能对自己和他人造成危险的水平,接下来就需要了解如何通过使用别名来让环境变得更安全、更友好以保护自己了。


via: https://www.linux.com/blog/learn/2018/12/bash-variables-environmental-and-otherwise

作者:Paul Brown 选题:lujun9972 译者:HankChow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

众所周知,bash(the Bourne-Again Shell)是目前绝大多数 Linux 发行版使用的默认 shell。本文将会介绍如何通过添加颜色和样式来自定义 bash 命令提示符的显示。尽管很多插件或工具都可以很轻易地满足这一需求,但我们也可以不使用插件和工具,自己手动自定义一些基本的显示方式,例如添加或者修改某些元素、更改前景色、更改背景色等等。

在 Linux 中自定义 bash 命令提示符

在 bash 中,我们可以通过更改 $PS1 环境变量的值来自定义 bash 命令提示符。

一般情况下,bash 命令提示符会是以下这样的形式:

在上图这种默认显示形式当中,“sk” 是我的用户名,而 “ubuntuserver” 是我的主机名。

只要插入一些以反斜杠开头的特殊转义字符串,就可以按照你的喜好修改命令提示符了。下面我来举几个例子。

在开始之前,我强烈建议你预先备份 ~/.bashrc 文件。

$ cp ~/.bashrc ~/.bashrc.bak

更改 bash 命令提示符中的 username@hostname 部分

如上所示,bash 命令提示符一般都带有 “username@hostname” 部分,这个部分是可以修改的。

只需要编辑 ~/.bashrc 文件:

$ vi ~/.bashrc

在文件的最后添加一行:

PS1="ostechnix> "

将上面的 “ostechnix” 替换为任意一个你想使用的单词,然后按 ESC 并输入 :wq 保存、退出文件。

执行以下命令使刚才的修改生效:

$ source ~/.bashrc

你就可以看见 bash 命令提示符中出现刚才添加的 “ostechnix” 了。

再来看看另一个例子,比如将 “username@hostname” 替换为 “Hello@welcome>”。

同样是像刚才那样修改 ~/.bashrc 文件。

export PS1="Hello@welcome> "

然后执行 source ~/.bashrc 让修改结果立即生效。

以下是我在 Ubuntu 18.04 LTS 上修改后的效果。

仅显示用户名

如果需要仅显示用户名,只需要在 ~/.bashrc 文件中加入以下这一行。

export PS1="\u "

这里的 \u 就是一个转义字符串。

下面提供了一些可以添加到 $PS1 环境变量中的用以改变 bash 命令提示符样式的转义字符串。每次修改之后,都需要执行 source ~/.bashrc 命令才能立即生效。

显示用户名和主机名

export PS1="\u\h "

命令提示符会这样显示:

skubuntuserver

显示用户名和完全限定域名

export PS1="\u\H "

在用户名和主机名之间显示其它字符

如果你还需要在用户名和主机名之间显示其它字符(例如 @),可以使用以下格式:

export PS1="\u@\h "

命令提示符会这样显示:

sk@ubuntuserver

显示用户名、主机名,并在末尾添加 $ 符号

export PS1="\u@\h\\$ "

综合以上两种显示方式

export PS1="\u@\h> "

命令提示符最终会这样显示:

sk@ubuntuserver>

相似地,还可以添加其它特殊字符,例如冒号、分号、星号、下划线、空格等等。

显示用户名、主机名、shell 名称

export PS1="\u@\h>\s "

显示用户名、主机名、shell 名称以及 shell 版本

export PS1="\u@\h>\s\v "

bash 命令提示符显示样式:

显示用户名、主机名、当前目录

export PS1="\u@\h\w "

如果当前目录是 $HOME ,会以一个波浪线(~)显示。

在 bash 命令提示符中显示日期

除了用户名和主机名,如果还想在 bash 命令提示符中显示日期,可以在 ~/.bashrc 文件中添加以下内容:

export PS1="\u@\h>\d "

在 bash 命令提示符中显示日期及 12 小时制时间

export PS1="\u@\h>\d\@ "

显示日期及 hh:mm:ss 格式时间

export PS1="\u@\h>\d\T "

显示日期及 24 小时制时间

export PS1="\u@\h>\d\A "

显示日期及 24 小时制 hh:mm:ss 格式时间

export PS1="\u@\h>\d\t "

以上是一些常见的可以改变 bash 命令提示符的转义字符串。除此以外的其它转义字符串,可以在 bash 的 man 手册 PROMPTING 章节中查阅。

你也可以随时执行以下命令查看当前的命令提示符样式。

$ echo $PS1

在 bash 命令提示符中去掉 username@hostname 部分

如果我不想做任何调整,直接把 username@hostname 部分整个去掉可以吗?答案是肯定的。

如果你是一个技术方面的博主,你有可能会需要在网站或者博客中上传自己的 Linux 终端截图。或许你的用户名和主机名太拉风、太另类,不想让别人看到,在这种情况下,你就需要隐藏命令提示符中的 “username@hostname” 部分。

如果你不想暴露自己的用户名和主机名,只需要按照以下步骤操作。

编辑 ~/.bashrc 文件:

$ vi ~/.bashrc

在文件末尾添加这一行:

PS1="\W> "

输入 :wq 保存并关闭文件。

执行以下命令让修改立即生效。

$ source ~/.bashrc

现在看一下你的终端,“username@hostname” 部分已经消失了,只保留了一个 ~> 标记。

如果你想要尽可能简单的操作,又不想弄乱你的 ~/.bashrc 文件,最好的办法就是在系统中创建另一个用户(例如 “user@example”、“admin@demo”)。用带有这样的命令提示符的用户去截图或者录屏,就不需要顾虑自己的用户名或主机名被别人看见了。

警告:在某些情况下,这种做法并不推荐。例如像 zsh 这种 shell 会继承当前 shell 的设置,这个时候可能会出现一些意想不到的问题。这个技巧只用于隐藏命令提示符中的 “username@hostname” 部分,仅此而已,如果把这个技巧挪作他用,也可能会出现异常。

为 bash 命令提示符着色

目前我们也只是变更了 bash 命令提示符中的内容,下面介绍一下如何对命令提示符进行着色。

通过向 ~/.bashrc 文件写入一些配置,可以修改 bash 命令提示符的前景色(也就是文本的颜色)和背景色。

例如,下面这一行配置可以令某些文本的颜色变成红色:

export PS1="\u@\[\e[31m\]\h\[\e[m\] "

添加配置后,执行 source ~/.bashrc 立即生效。

你的 bash 命令提示符就会变成这样:

类似地,可以用这样的配置来改变背景色:

export PS1="\u@\[\e[31;46m\]\h\[\e[m\] "

添加 emoji

大家都喜欢 emoji。还可以按照以下配置把 emoji 插入到命令提示符中。

PS1="\W ♤ >"

需要注意的是,emoji 的显示取决于使用的字体,因此某些终端可能会无法正常显示 emoji,取而代之的是一些乱码或者单色表情符号。

自定义 bash 命令提示符有点难,有更简单的方法吗?

如果你是一个新手,编辑 $PS1 环境变量的过程可能会有些困难,因为命令提示符中的大量转义字符串可能会让你有点晕头转向。但不要担心,有一个在线的 bash $PS1 生成器可以帮助你轻松生成各种 $PS1 环境变量值。

就是这个网站

EzPrompt

只需要直接选择你想要的 bash 命令提示符样式,添加颜色、设计排序,然后就完成了。你可以预览输出,并将配置代码复制粘贴到 ~/.bashrc 文件中。就这么简单。顺便一提,本文中大部分的示例都是通过这个网站制作的。

我把我的 ~/.bashrc 文件弄乱了,该如何恢复?

正如我在上面提到的,强烈建议在更改 ~/.bashrc 文件前做好备份(在更改其它重要的配置文件之前也一定要记得备份)。这样一旦出现任何问题,你都可以很方便地恢复到更改之前的配置状态。当然,如果你忘记了备份,还可以按照下面这篇文章中介绍的方法恢复为默认配置。

这篇文章是基于 ubuntu 的,但也适用于其它的 Linux 发行版。不过事先声明,这篇文章的方法会将 ~/.bashrc 文件恢复到系统最初时的状态,你对这个文件做过的任何修改都将丢失。

感谢阅读!


via: https://www.ostechnix.com/hide-modify-usernamelocalhost-part-terminal/

作者:SK 选题:lujun9972 译者:HankChow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出