Shell中的特殊符号(special characters)和含义

之前写过两篇关于Bash语法的blog,分别是:

个人感觉,想要通畅地读懂bash脚本,还差一个部分,那就是符号。

个人网上的讲bash符号的文章有点乱,要么有错,要么不全,要么太深,看了也感觉用不上。很多英文的文章写的好,写的深,但是查阅起来不方便。于是,干脆我自己写一篇吧,不说我这篇写的有多好,起码名称中英文有个对应,有一些自己动手运行验证过了的小例子,很多技术细节我也注明了出处。将来如果有对细节进一步的查阅的需要,可以从这里开始。

# 井号 (crosshatch/sharp/hash)

  1. 井号开头的语句被视为代码的注释,不会被执行。

  2. 在 #!/bin/bash 中,脚本文件开头首行的#!会告诉系统这个文件是一系列命令的集合,应该被发送给#!后面指定的解释器来执行。大概都有哪些解释器呢?如下:

  3. #!/bin/sh :Executes the script using the Bourne shell or a compatible shell, with path /bin/sh

  4. #!/bin/bash :Executes the script using the Bash shell.
  5. #!/bin/csh -f :Executes the script using C shell or a compatible shell.
  6. #!/usr/bin/perl -T :Executes the script using perl with the option of taint checks
  7. #!/usr/bin/env python :Executes the script using python by looking up the path to the python interpreter automatically from the environment variables

~ 波浪号(tilde)

Bash提供了一些用~开头的变量,这些变量的展开叫做Tilde Expansions,也就是将这些缩写转换成它们代表的目录名称的过程。

  1. 与$HOME一样,代表当前用户的home directory.

  2. ~username, 代表其他某用户的home directory.

  3. ~+, 代表当前的工作目录, 与$PWD一样。

  4. ~-,代表上一个工作目录,与$OLDPWD一样。

  5. ~1, ~2, ~-1, ~-0 分别代表目录栈中的编号为1的,编号为2的,编号为倒数第2的,倒数第一的目录。相当于’dirs +1’, ‘dirs +2’, ‘dirs -1’, ‘dirs –0’.

; 分号(semicolon)

分号用来分隔两个命令,比如命令 echo a; echo b 就是告诉bash,echo a 和 echo b 是两个不同的命令,需要一个接一个地分开运行。参考这里

;; 双分号(double semicolon)

双分号;; 仅用在case结构中,标志一个选项的结束,类似于C语言中的break。

. 点号(dot)

一个 dot 代表当前目录,两个 dot 代表上层目录。如果档案名称以 dot 开头,该档案就属特殊档案,用 ls 指令必须加上 -a 选项才会显示。除此之外,在 regular expression 中,一个 dot 代表匹配一个字元。

‘string’ 单引号 (single quote)
被单引号用括住的内容,将被视为单一字串。在引号内的代表变量的$符号,没有作用,也就是说,$符号被视为一般符号处理,防止任何变量替换。

“string” 双引号 (double quote)
被双引号用括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。这点与单引数的处理方式不同。

command 反引号 (backtick)

反引号不是一种引号,它有特殊的意义。任何被反引号括起来的东西都会在主命令执行之前先被shell求值(或执行),并且反引号括起来的东西的求值(或执行)的输出会被主命令使用到。

在前面的单双引号,括住的是字串,但如果该字串是一列命令列,会怎样?命令会执行么?

答案是不会执行。要处理这种情况,我们得用反引号。

在反引号内的 date +%F 会被视为指令,执行的结果会带入 $fdv 变量中。

下面的例子里,先创建一个名为lucky的user,可以看到他的uid为1001.

查看当前用户的信息,名为yunlong的用户的uid为1000. 可以看到/home/lucky 是lucky用户的home directory,owner是lucky。

然后,我们利用命令 chown id -u /home/lucky, 把/home/lucky的owner换成了yunlong。注意这里对于反引号的使用。

, 逗号 (comma)

逗号可以有下面这些用途:

  1. 括号扩展(brace expansion)

tee 命令的作用是从标准输入读取(standard input)之后,将读取来的信息同时写入标准输出(standard output)和一个或多个文件中。详情见这里

  1. 在let语句中,或者在与其作用等价的(())构造中分隔算数操作。

  2. 可以在for语句中,分隔不同的index变量,避免在for循环体中进行操作。

  3. 逗号还可以用在Bash4中,把字符串变成小写。

/ 斜杠 (forward slash)

在路径表示时,斜杠代表目录。通常单一的斜杠 / 代表 root 根目录的意思;在四则运算中,斜杠代表除法的符号。

\ 反斜杠(backslash/escape)

在交互模式下的escape符号,有几个作用:

  1. 放在指令前,有取消 aliases 的作用;

type rm

rm is aliased to `rm -i’
\rm .*.log
上例,作者在 rm 指令前加上 escape 字符,作用是暂时取消别名的功能,将 rm 指令还原。

  1. 转义字符,放在特殊符号前,则该特殊符号的作用消失;

  2. 放在指令的最末端,表示指令连接下一行。

| 竖线 bar/pipe/vertical bar

pipeline 是 UNIX 系统,基础且重要的观念。连结上个指令的标准输出,做为下个指令的标准输入。

善用这个观念,对精简 script 有相当的帮助。

! 叹号 exclamation mark/bang

通常它代表反逻辑的作用,譬如条件侦测中,用 != 来代表”不等于”

if [ “$?” != 0 ] ; then echo “Executes error”; elif then echo “Executes successfully”; fi;

这个例子里,除了展示了叹号的用法,还包含了如何把if语句写在一行里的方法,还有一个利用上面讲过的反斜杠把一个一行的if语句写成多行的方法。

在正则表达式里,可以使用 !字符在正则表达式之前对其求反。也就是说,仅当字符串与表达式的其余部分不匹配时,才认为字符串已匹配。

注意,网上的很多名为《shell脚本中一些特殊符号》的文章里,在讲叹号是给出的例子里使用叹号是不正确的。

应该使用^符号,来对字符范围取反。如下:

: 冒号 colon

在 bash 中,这是一个内建指令, 这个指令”什么事都不干(no-op)”,但返回状态值 0 (Bash里返回值为0表示正常执行结束,非0表示出了问题)。

比如,if语句利用上冒号可以写成这样:

if [ “$?” != 0 ]; then :; else echo “Execute successfully”; fi

? 问号 (question mark)

在文件名的匹配中,用作单字符的通配符。注意,问号代表的是只有一个字符的通配符,数字和字母都可以匹配。

* 星号 (asterisk/star)

星号是bash中的任意字符序列通配符,包括没有字符的情况都可以匹配。

** 双星号 (double-asterisk)

双星号(**)在多个段中尝试匹配零个或多个字符,它用于对嵌套目录中的文件进行通配。

举例:

Tests/*/.js

这里,匹配的文件被限制在Test目录中。会被匹配的文件包括 Tests/HelloWorld.js, Tests/UI/HelloWorld.js, Tests/UI/Feature1/HelloWorld.js

另一个就是幂运算。

$ 美元符号(dollar sign)
变量替换(Variable Substitution)的代表符号。 一个变量名字前面带上美元符号,表明这是个变量。可以用美元符带上这个变量的名字对其进行引用。
另外,在 Regular Expressions 里被定义为匹配行尾 (end-of-line)。

${} 变量扩展(variable substitution)

${ }用于变量替换。一般情况下,$var 与${var} 并没有啥不一样。但是用 ${ } 会比较精确的界定变量名称的范围。

$ AB=string0
$ A=string1
$ echo $AB
string0
原本是打算先将 $A 的结果替换出来,然后再补一个 B 字母于其后.

但在命令行上,真正的结果却是只会提换变量名称为 AB 的值出来…

若使用 ${ } 就没问题了:
$ echo ${A}B
string1B

$() 命令替换 (command substitution,与一对反引号相同)

在 bash shell 中,$( ) 与 (反引号) 都是用来做命令替换用(command substitution)的。

例如version=$(uname -r)和version=uname -r都可以是version得到内核的版本号。

  1. 反引号的命令替换基本上可在全部的 unix shell 中使用,若写成 shell script ,其移植性比较高。但是,反引号容易打错或看错。

  2. $()并不是所有shell都支持。

$(()) 和 $[] 算数扩展(arithmetic expansion)

它们是一样的,都是进行数学运算的。支持+ – * / %:分别为 “加、减、乘、除、取模”。但是注意,bash只能作整数运算,对于浮点数是当作字符串处理的。

二者的区别是$[]已经是淘汰的,弃用的语法了,现在已经完全被$(())替代了。

() 小括号(parentheses) 指令群组 (command group)

小括号之内的一系列命令,会在一个新创建的subshell中执行。由于小括号内的命令是在subshell中执行的,所以其内部的变量赋值在执行之后不会持续。

Placing a list of commands between parentheses causes a subshell environment to be created (see Command Execution Environment), and each of the commands in list to be executed in that subshell. Since the list is executed in a subshell, variable assignments do not remain in effect after the subshell completes.

{} 花括号(braces)指令群组 (command group)

花括号之内的一系列指令会在当前的shell的上下文中执行。不会创建subshell。 列表之后的分号(或者换行)是必须要有的。

Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created. The semicolon (or newline) following list is required.

(()) 双括号 (Double-Parentheses)

跟let命令一样,双括号允许在其中进行算数扩展和求值。 最简单的一个例子, a=$((5+3)), 会将5+3的结果赋值给a。 双括号还是一个在bash中使用的C语言风格的操作变量的方法,举个例子 ((var++)).

[] 单方括号 (Single Square Brackets)

单方括号是内置命令test的另一种形式,方括号括住的命令会被验证其是否为真。 注意,空字符串为false,非空字符串为true。

既然是test命令的另一种形式,那么test命令的各种选项就也是可以应用的。

[[]] 双方括号 (Double Square Brackets)

[[ 是新的,提高版的[, 双方括号是个关键字,不是一个程序。双方框更好用,比较见下表。

英文原文如下:

[ : test implements the old, portable syntax of the command. In almost all shells (the oldest Bourne shells are the exception), [ is a synonym for test (but requires a final argument of ]).

[[ : is a new, improved version of it, and it is a keyword rather than a program. This makes it easier to use

&& 逻辑与, || 逻辑或 (Logical Operators)

双&&符号在Bash中意思是逻辑与(AND),并且可以用来分隔几个顺序执行的命令。

举例:

cd /root/ && echo "I've got root"

& 后台工作 (Single Ampersand)

在Bash中, &是控制字符,放在命令的末尾,其作用是让命令在后台运行,也就是说在另外的一个subshell里,以异步的方式,如同一个job一样的执行。当前的Shell会立即回到等待用户输入的状态,并且返回值为0.

举例:

shell会给出后台运行命令的process ID (PID), 这个ID会存储在$! 变量中。

$ ./myscript.py &
[1] 1337

后面可以通过$!变量对该进程进行引用。
$ echo $!

1337

一旦生成了新的后台进程,这个进程会出现在job列表中。
$ jobs
[1]+ Running ./myscript.py &

foregroud命令可以把这个进程拿回前台。
fg

  • 加号, -减号, * 乘号, / 除号

比较简单,不说了。

= 等号(赋值), == 双等号 (判断相等), != 不等于号

简单,也不说了。

^ 折音号 (circumflex/caret)

这个符号在正则表达式中,代表行的开头位置,在[]中也与!(叹号)一样表示非,即求反。

>, >>,

这里符号比较多,一个一个简介吧。

  1. command > file — 将输出重定向到file

  2. command < file — 将输入重定向到file,确切的说是把file中的内容拿来作为command的输入。

  3. command >> file — 将输出以追加的方式重定向到file

  4. n >& m — 将输出文件m和n合并

  5. n

Original: https://www.cnblogs.com/awpatp/p/14146625.html
Author: 中道学友
Title: Shell中的特殊符号(special characters)和含义

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/529593/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 内存管理-物理内存虚拟内存布局

    ARM-linux环境,物理内存和虚拟内存之间的映射关系: Original: https://www.cnblogs.com/fanguang/p/11930358.htmlAu…

    Linux 2023年6月6日
    091
  • Flink 如何分流数据

    场景 分流方式 如何分流 使用Filter分流 使用Split分流 使用Side Output分流 场景 获取流数据的时候,通常需要根据所需把流拆分出其他多个流,根据不同的流再去作…

    Linux 2023年6月7日
    0134
  • Spring Boot 项目部署到 Linux服务器

    1.首先将SpringBoot项目打包成JAR包,然后通过FTP工具上传到Linux,执行如下命令: java -jar xxx.jar & 该命令执行后,启动jar,一旦…

    Linux 2023年6月14日
    072
  • windows下使用route添加路由

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月7日
    0106
  • Python代码模板

    #!/usr/bin/env python -*- encoding: utf-8 -*- class ClassName: def __init__(self, arg1, ar…

    Linux 2023年6月14日
    091
  • 一篇”水文“带你解剖HTML中的ID属性以及和Class属性的区别。

    写在开篇 哈喽!我又来写”水文”了,回顾上篇讲到的class属性,那么class属性和本篇要讲的id属性有什么不一样呢?跟随笔者步伐,一一解剖。 HTML中…

    Linux 2023年6月7日
    0101
  • Java对象序列化和反序列化

    Java类的序列化和反序列化 序列化:指将对象转换为字节序列的过程,也就是将对象的信息转换成文件保存。 反序列化:将字节序列转换成目标对象的过程,也就是读取文件,并转换为对象。 几…

    Linux 2023年6月14日
    0104
  • 保罗·艾伦的故事

    上周,保罗·艾伦逝世。《财新周刊》约我写一篇纪念文章,发表在他们杂志上面 一些个人新闻:最近,我了解到我在2009年与之抗争的非霍奇金淋巴瘤已经复发。我已经开始治疗,我的医生很乐观…

    Linux 2023年6月14日
    0112
  • CentOS 7替换默认软件源

    安装CentOS 7后,默认源在国外,可以替换为国内的源以提升访问速度 参考https://mirrors.ustc.edu.cn/help/centos.html sudo vi…

    Linux 2023年6月6日
    087
  • python写日志

    写日志的办法多种多样,我这个是我喜欢的办法,可以做个参考 没啥说的,直接上代码 import time def write_log(value): now_time = time….

    Linux 2023年6月6日
    087
  • 关于最近公司一个业务系统的性能优化方案

    一个刚上线的IT系统,往往负载压力不大,所以不会存在什么性能问题。这时,人们大多只关心系统的功能性和用户体验。但是,随着时间推移,用户量和数据量都比刚上线的时候要多很多,高并发和大…

    Linux 2023年6月6日
    0102
  • Git的使用以及常用命令(详解)

    一、 版本控制工具 什么是版本控制系统? 版本控制系统(Version Control System):是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。版本控…

    Linux 2023年6月6日
    0111
  • Linux 配置Maven(避免踩坑篇)

    前言:请各大网友尊重本人原创知识分享,谨记本人博客: 南国以南i 二、下载好的maven安装包放在磁盘的 /usr/local/ 目录下,如下图: 三、解压该压缩文件 tar -z…

    Linux 2023年5月27日
    099
  • 微信开发之微信分享 + php

    html DOCTYPE html> <html> <head> <meta http-equiv="content-type&quo…

    Linux 2023年6月7日
    0103
  • oracle ORA-31655

    原因:是因为不是同一个schema,导致的问题产生 解决方案: 在导入语句最后添加上remap_schema=old:new 着old是原schema,也就是导出的用户名,new是…

    Linux 2023年6月8日
    086
  • C++ 之处理模板化基类的成员名称

    问题描述 假设有下面这么一段简单的代码,其中定义了两个类模板,一个基类 Animal,一个派生类 Dog: #include #include using namespace st…

    Linux 2023年6月7日
    099
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球