shell学习

  • shell学习已关闭评论
  • 199 次浏览
  • A+
所属分类:linux技术
摘要

  Shell 本身是一个用 C 语言编写的程序,是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解释并传给系统,它是用户使用 Linux 的桥梁,是UNIX/Linux系统的用户与操作系统之间的一种接口。


1、什么是shell和shell脚本

  Shell 本身是一个用 C 语言编写的程序,是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解释并传给系统,它是用户使用 Linux 的桥梁,是UNIX/Linux系统的用户与操作系统之间的一种接口。

这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。Shell是操作系统的接口,是用户与操作系统交互的桥梁。

Shell既是一种命令语言,又是一种程序设计语言(shell脚本)。它虽然不是 Linux系统内核的一部分,但它调用了系统内核的大部分功能来执行程序、创建文档并以并行的方式协调各个程序的运行。

  它既是终端上的用户与UNIX/Linux操作系统交互的命令解释程序(shell命令)又是一种高级的命令程序设计语言(shell脚本)

  作为命令解释程序,shell接收用户输入的命令语言,将命令翻译成一个动作序列,然后调用系统过程执行这条命令。

  作为命令程序设计语言,shell具有一般高级语言的许多特征,如变量定义、赋值、条件和循环语句等。用户可以利用SHELL的这些功能将多条命令组织成一个命令程序,以完成某种特定的任务。这个命令程序称为shell程序或shell过程。

shell学习

参考:https://www.cnblogs.com/The-explosion/articles/12336061.html

 

2、关于shell的变量设置

1.变量与变量内容以一个等号“=”来链接,如下所示:
“myname=VBird”

2.等号两边不能直接接空白字符,如下所示为错误:
“myname = VBird”或“myname=VBird Tsai”

3.变量名称只能是英文字母与数字,但是开头字符不能是数字,如下为错误:
“2myname=VBird”

4.变量内容若有空白字符可使用双引号“"”或单引号“'”将变量内容结合起来,但
#双引号内的特殊字符如 $等,可以保有原本的特性,如下所示:
“var="lang is $LANG"”则“echo $var”可得“lang is zh_TW.UTF-8”

#单引号内的特殊字符则仅为一般字符(纯文本),如下所示:
“var='lang is $LANG'”则“echo $var”可得“lang is $LANG”

5.可用转义符“ ”将特殊符号(如 [Enter], $, ,空白字符, '等)变成一般字符,如:
“myname=VBird Tsai”

6.在一串指令的执行中,还需要借由其他额外的指令所提供的信息时,可以使用反单
引号`指令`”或“$(指令)”。特别注意,那个 `是键盘上方的数字键 1左边那个按
键,而不是单引号!例如想要取得核心版本的设置:
“version=$(uname -r)”再“echo $version”可得“3.10.0-229.el7.x86_64”

注:在一串指令中,在` `之内的指令将会被先执行,而其执行出来的结果将做为外部的输入信息

7.若该变量为扩增变量内容时,则可用 "$变量名称"${变量}累加内容,如下所
示:
“PATH="$PATH":/home/bin”或“PATH=${PATH}:/home/bin”或  "PATH=$PATH:/home/bin”

8.若该变量需要在其他子程序执行,则需要以 export来使变量变成环境变量:
export PATH”实现"分享自己的变量设置给后来调用的文件或其他程序。"

9.通常大写字符为系统默认变量,自行设置变量可以使用小写字符,方便判断(纯
粹依照使用者兴趣与嗜好);

10.取消变量的方法为使用 unset:“unset变量名称”例如取消 myname的设置:
“unset myname”

代码示例
范例一:设置一变量 name,且内容为 VBird [dmtsai@study ~]$ 12name=VBird bash: 12name=VBird: command not found... <==屏幕会显示错误!因为不能以数字开头! [dmtsai@study ~]$ name = VBird <==还是错误!因为有空白! [dmtsai@study ~]$ name=VBird <==OK的啦! 范例二:承上题,若变量内容为 VBird's name呢,就是变量内容含有特殊符号时: [dmtsai@study ~]$ name=VBird's name #单引号与双引号必须要成对,在上面的设置中仅有一个单引号,因此当你按下 enter后, #你还可以继续输入变量内容。这与我们所需要的功能不同,失败啦! #记得,失败后要复原请按下 [ctrl]-c结束! [dmtsai@study ~]$ name="VBird's name" <==OK的啦! #指令是由左边向右找→,先遇到的引号先有用,因此如上所示,单引号变成一般字符! [dmtsai@study ~]$ name='VBird's name' <==失败的啦! #因为前两个单引号已成对,后面就多了一个不成对的单引号了!因此也就失败了! [dmtsai@study ~]$ name=VBird's name <==OK的啦! #利用反斜线()跳脱特殊字符,例如单引号与空白键,这也是 OK的啦! 范例三:我要在 PATH这个变量当中“累加”:/home/dmtsai/bin这个目录 [dmtsai@study ~]$ PATH=$PATH:/home/dmtsai/bin [dmtsai@study ~]$ PATH="$PATH":/home/dmtsai/bin [dmtsai@study ~]$ PATH=${PATH}:/home/dmtsai/bin #上面这三种格式在 PATH里头的设置都是 OK的!但是下面的例子就不见得啰! 范例四:承范例三,我要将 name的内容多出 "yes"呢? [dmtsai@study ~]$ name=$nameyes #知道了吧?如果没有双引号,那么变量成了啥?name的内容是 $nameyes这个变量! #呵呵!我们可没有设置过 nameyes这个变量呐!所以,应该是下面这样才对! [dmtsai@study ~]$ name="$name"yes [dmtsai@study ~]$ name=${name}yes <==以此例较佳! 范例五:如何让我刚刚设置的 name=VBird可以用在下个 shell的程序? [dmtsai@study ~]$ name=VBird [dmtsai@study ~]$ bash <==进入到所谓的子程序 [dmtsai@study ~]$ echo $name <==子程序:再次的 echo一下; <==嘿嘿!并没有刚刚设置的内容喔! [dmtsai@study ~]$ exit <==子程序:离开这个子程序 [dmtsai@study ~]$ export name [dmtsai@study ~]$ bash <==进入到所谓的子程序 [dmtsai@study ~]$ echo $name <==子程序:在此执行! VBird <==看吧!出现设置值了! [dmtsai@study ~]$ unset name <==最后用unset命令取消变量值

3、shell中常见环境变量

用 env 或 export 观察环境变量与常见环境变量说明 范例一:列出目前的 shell环境下的所有环境变量与其内容。 [dmtsai@study ~]$ env HOSTNAME=study.centos.vbird <==这部主机的主机名称 TERM=xterm                  <==这个终端机使用的环境是什么类型 SHELL=/bin/bash             <==目前这个环境下,使用的 Shell是哪一个程序? HISTSIZE=1000               <==“记录指令的笔数”在 CentOS默认可记录 1000笔 OLDPWD=/home/dmtsai         <==上一个工作目录的所在 LC_ALL=en_US.utf8           <==由于语系的关系,鸟哥偷偷丢上来的一个设置 USER=dmtsai                 <==使用者的名称啊! LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01: or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32: *.tar=01...                 <==一些颜色显示 MAIL=/var/spool/mail/dmtsai <==这个使用者所取用的 mailbox位置 PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin PWD=/home/dmtsai            <==目前使用者所在的工作目录(利用 pwd取出!) LANG=zh_TW.UTF-8            <==这个与语系有关,下面会再介绍! HOME=/home/dmtsai           <==这个使用者的主文件夹啊! LOGNAME=dmtsai              <==登陆者用来登陆的帐号名称 _=/usr/bin/env              <==上一次使用的指令的最后一个参数(或指令本身)

3.1 用set查看全部变量

[dmtsai@study ~]$ set               #查看所有变量(含环境变量和自订变量) BASH=/bin/bash                      <== bash的主程序放置路径 BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu") BASH_VERSION='4.2.46(1)-release'  <==这两行是 bash的版本 COLUMNS=90                          <==在目前的终端机环境下,使用的字段有几个字符长度 HISTFILE=/home/dmtsai/.bash_history <==历史命令记录的放置文件,隐藏文件 HISTFILESIZE=1000                   <==存起来(与上个变量有关)的文件之指令的最大纪录笔数。 HISTSIZE=1000                       <==目前环境下,内存中记录的历史命令最大笔数。 IFS=$' tn'                        <==默认的分隔符号 LINES=20                            <==目前的终端机下的最大行数 MACHTYPE=x86_64-redhat-linux-gnu    <==安装的机器类型 OSTYPE=linux-gnu                    <==操作系统的类型! PS1='[u@h W]$ '                 <== PS1是命令提示字符,也就是我们常见的[root@www ~]                                     #或 [dmtsai ~]$的设置值啦!可以更动的! PS2='> '                            <==如果你使用转义符号()第二行以后的提示字符也 $                                   <==目前这个 shell所使用的 PID ?                                   <==刚刚执行完指令的回传值。

3.2 PSI值

d:  #可显示出“星期月日”的日期格式,如:"Mon Feb 2" H:  #完整的主机名称。举例来说,鸟哥的练习机为“study.centos.vbird” h:  #仅取主机名称在第一个小数点之前的名字,如鸟哥主机则为“study”后面省略 t:  #显示时间,为 24小时格式的“HH:MM:SS” T:  #显示时间,为 12小时格式的“HH:MM:SS” A:  #显示时间,为 24小时格式的“HH:MM” @:  #显示时间,为 12小时格式的“am/pm”样式 u:  #目前使用者的帐号名称,如“dmtsai”; v:  #BASH的版本信息,如鸟哥的测试主机版本为 4.2.46(1)-release,仅取“4.2”显示 w:  #完整的工作目录名称,由根目录写起的目录名称。但主文件夹会以 ~取代; W:  #利用 basename函数取得工作目录名称,所以仅会列出最后一个目录名。 #:  #下达的第几个指令。 $:  #提示字符,如果是 root时,提示字符为 #,否则就是 $啰~ CentOS默认的 PS1内容:"[u@h W]$ "

当然也可任意设置,如:

[zengcj@localhost ~]$ PS1='[u@h w A ##]$ ' [zengcj@localhost ~ 14:58 #48]$ ls Docker  Exercise  genomic  GWAS  miniconda3  n.sh  SMR  software  下载  公共  图片  文档  桌面  模板  视频  音乐 [zengcj@localhost ~ 14:59 #49]$ PS1='[u@h w A ]$ ' [zengcj@localhost ~ ]$ PS1='[xiangsui@h w ]$ ' [xiangsui@localhost ~ ]$ PS1='[xiangsui@h w ]$' [xiangsui@localhost ~ ]$PS1='[xiangsui@^_^ w ]$' #一般最后引号前需多一个空格 [xiangsui@^_^ ~ ]$PS1='[xiangsui@^_^ w ]$ ' [xiangsui@^_^ ~ ]$ PS1="[xiangsui@^_^ w ]$ "

3.3 其他

$:(关于本 shell的 PID)
$字号本身也是个变量,代表的是“目前这个 Shell的线程代号”,亦即是所谓的 PID(Process ID)。更多的程序观念,我们会在第四篇的时候提及。想要知道我们的 shell的 PID,就可以用:“ echo $$”即可!出现的数字就是你的 PID号码。
?:(关于上个执行指令的回传值)
在 bash里面这个变量可重要的很!这个变量是:“上一个执行的指令所回传的值”,上面这句话的重点是“上一个指令”与“回传值”两个地方。当我们执行某些指令时,这些指令都会回传一个执行后的代码。一般来说,如果成功的执行该指令,则会回传一个 0值,如果执行过程发生错误,就会回传“错误代码”,可以根据回传错误代码的不同,判断发生的错误类型。

 用以下程序判断错误代码含义

#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h>  int main() {     int i=0;     for(i=0;i<43;i++) //43及以后就木有了         printf("errno:%d:t%sn",i,strerror(i));     return 0; }

 参考:https://www.cnblogs.com/castor-xu/p/12026515.html

3.4 关于Linux支持的语系

--  可以用locale -a查询,语系文件一般放在 /usr/lib/locale/ 目录,系统默认语系定义为/etc/locale.conf

[xiangsui@^_^ ~]$ locale <==后面不加任何选项与参数即可! LANG=en_US <==主语言的环境 LC_CTYPE="en_US" <==字符(文字)辨识的编码 LC_NUMERIC="en_US" <==数字系统的显示讯息 LC_TIME="en_US" <==时间系统的显示数据 LC_COLLATE="en_US" <==字串的比较与排序等 LC_MONETARY="en_US" <==币值格式的显示等 LC_MESSAGES="en_US" <==讯息显示的内容,如功能表、错误讯息等 LC_ALL= <==整体语系的环境

基本上,你可以逐一设置每个与语系有关的变量数据,但事实上,如果其他的语系变量都未设置,且你有设置 LANG或者是 LC_ALL时,则其他的语系变量就会被这两个变量所取代!这也是为什么我们在 Linux当中,通常说明仅设置 LANGLC_ALL这两个变量而已,因为他是最主要的设置变量!你是在 MS Windows主机以远端连线服务器的软件连线到主机的话,其实命令行确实是可以看到中文的。此时反而你得要在 LC_ALL设置中文编码!

4、变量键盘读取、阵列与宣告: read, array, declare

-- read

[dmtsai@study ~]$ read [-pt] variable 选项与参数: -p :后面可以接提示字符! -t :后面可以接等待的“秒数!”这个比较有趣~不会一直等待使用者啦! 范例一:让使用者由键盘输入一内容,将该内容变成名为 atest的变量 [dmtsai@study ~]$ read atest This is a test <==此时光标会等待你输入!请输入左侧文字看看 [dmtsai@study ~]$ echo ${atest} This is a test <==你刚刚输入的数据已经变成一个变量内容! 范例二:提示使用者 30秒内输入自己的大名,将该输入字串作为名为 named的变量内容 [dmtsai@study ~]$ read -p "Please keyin your name: " -t 30 named Please keyin your name: VBird Tsai <==注意看,会有提示字符喔! [dmtsai@study ~]$ echo ${named} VBird Tsai <==输入的数据又变成一个变量的内容了!

read之后不加任何参数,直接加上变量名称,那么下面就会主动出现一个空白行等待你的输入(如范例一)。如果加上 -t后面接秒数,例如上面的范例二,那么 30秒之内没有任何动作时,该指令就会自动略过了~如果是加上 -p,嘿嘿!在输入的光标前就会有比较多可以用的提示字符给我们参考!在指令的下达里面,比较美观啦! ^_^

-- declare / typeset

declare或 typeset是一样的功能,就是在“宣告变量的类型”。如果使用 declare后面并没有接任何参数,那么 bash就会主动的将所有的变量名称与内容通通列出来,就好像使用 set一样。

[dmtsai@study ~]$ declare [-aixr] variable 选项与参数: -a :将后面名为 variable的变量定义成为阵列(array)类型 -i :将后面名为 variable的变量定义成为整数数字(integer)类型 -x :用法与 export一样,就是将后面的 variable变成环境变量; -r :将变量设置成为 readonly类型,该变量不可被更改内容,也不能 unset 范例一:让变量 sum进行 100+300+50的加总结果 [dmtsai@study ~]$ sum=100+300+50 [dmtsai@study ~]$ echo ${sum} 100+300+50 <==咦!怎么没有帮我计算加总?因为这是文字体态的变量属性啊! [dmtsai@study ~]$ declare -i sum=100+300+50 [dmtsai@study ~]$ echo ${sum} 450 <==瞭乎??

由于在默认的情况下面, bash对于变量有几个基本的定义:

  • 变量类型默认为“字串”,所以若不指定变量类型,则 1+2为一个“字串”而不是“计算式”。所以上述第一个执行的结果才会出现那个情况的;
  • bash环境中的数值运算,默认最多仅能到达整数形态,所以 1/3结果是 0;
  • 如果需要非字串类型的变量,那就得要进行变量的宣告才行!
范例二:将 sum变成环境变量 [dmtsai@study ~]$ declare -x sum [dmtsai@study ~]$ export | grep sum declare -ix sum="450" <==果然出现了!包括有 i与 x的宣告! 范例三:让 sum变成只读属性,不可更动! [dmtsai@study ~]$ declare -r sum [dmtsai@study ~]$ sum=tesgting -bash: sum: readonly variable <==老天爷~不能改这个变量了! 范例四:让 sum变成非环境变量的自订变量吧! [dmtsai@study ~]$ declare +x sum <==将 -变成 +可以进行“取消”动作 [dmtsai@study ~]$ declare -p sum <== -p可以单独列出变量的类型 declare -ir sum="450" <==看吧!只剩下 i, r的类型,不具有 x啰!

-- 阵列(array)变量类型

在 bash中,阵列的设置方式是:var[index]=content

范例:设置var[1]~ var[3]的变量。 [dmtsai@study ~]$ var[1]="small min" [dmtsai@study ~]$ var[2]="big min" [dmtsai@study ~]$ var[3]="nice min" [dmtsai@study ~]$ echo "${var[1]}, ${var[2]}, ${var[3]}" small min, big min, nice min

5、与文件系统及程序的限制关系: ulimit

bash是可以“限制使用者的某些系统资源”的,包括可以打开的文件数量,可以使用的 CPU时间,可以使用的内存总量等等。主要依靠ulimit命令实现。

[dmtsai@study ~]$ ulimit [-SHacdfltu] [配额] 选项与参数: -H :hard limit,严格的设置,必定不能超过这个设置的数值; -S :soft limit,警告的设置,可以超过这个设置值,但是若超过则有警告讯息。 在设置上,通常 soft会比 hard小,举例来说,soft可设置为 80而 hard 设置为 100,那么你可以使用到 90(因为没有超过 100),但介于 80~100之间时, 系统会有警告讯息通知你! -a :后面不接任何选项与参数,可列出所有的限制额度; -c :当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用), 这种文件就被称为核心文件(core file)。此为限制每个核心文件的最大容量。 -f :此 shell可以创建的最大文件大小(一般可能设置为 2GB)单位为 KBytes -d :程序可使用的最大断裂内存(segment)容量; -l :可用于锁定(lock)的内存量 -t :可使用的最大 CPU时间(单位为秒) -u :单一使用者可以使用的最大程序(process)数量。 范例一:列出你目前身份(假设为一般帐号)的所有限制数据数值 [dmtsai@study ~]$ ulimit -a core file size (blocks, -c) 0 <==只要是 0就代表没限制 data seg size (kBytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited < ==可创建的单一文件的大小 pending signals (-i) 4903 max locked memory (kBytes, -l) 64 max memory size (kBytes, -m) unlimited open files (-n) 1024 < ==同时可打开的文件数量 pipe size (512 Bytes, -p) 8 POSIX message queues (Bytes, -q) 819200 real-time priority (-r) 0 stack size (kBytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 4096 virtual memory (kBytes, -v) unlimited file locks (-x) unlimited 范例二:限制使用者仅能创建 10MBytes以下的容量的文件 [dmtsai@study ~]$ ulimit -f 10240 [dmtsai@study ~]$ ulimit -a | grep 'file size' core file size (blocks, -c) 0 file size (blocks, -f) 10240 <==最大量为10240Kbyes,相当10MBytes [dmtsai@study ~]$ dd if=/dev/zero of=123 bs=1M count=20 File size limit exceeded(core dumped) <==尝试创建 20MB的文件,结果失败了! [dmtsai@study ~]$ rm 123 <==赶快将这个文件删除啰!同时你得要登出再次的登陆才能解开 10M的限制

注:想要复原 ulimit的设置最简单的方法就是登出再登陆,否则就是得要重新以ulimit设置才行!不过,要注意的是,一般身份使用者如果以 ulimit -f设置了的文件大小,那么他“只能继续减小文件大小,不能增加文件大小!”