Welcome to

快雪Tang

Home / 技术

Bash Tricks: string

Bash 字符串操作极其强大,尽管还无法和高级语言的能力相比肩,但在bash中你已经几乎可以完全操纵任何文本、任何字符串了。   字符串操作和变量有密切关联性,所以先介绍变量及其表达式的使用惯例: ${var} 变量var的值, 与$var相同 ${var-DEFAULT} 如果var没有被声明, 那么就以$DEFAULT作为其值;否则其值为 $var ${var:-DEFAULT} 如果var没有被声明, 或者其值为空, 那么就以$DEFAULT作为其值;否则其值为 $var ${var=DEFAULT} 如果var没有被声明, 那么就以$DEFAULT作为其值;否则其值为 $var ${var:=DEFAULT} 如果var没有被声明, 或者其值为空, 那么就以$DEFAULT作为其值;否则其值为 $var ${var+OTHER} 如果var声明了, 那么其值就是$OTHER;否则就为null字符串 ${var:+OTHER} 如果var被设置了, 那么其值就是$OTHER;否则就为null字符串 ${var?ERR_MSG} 如果var没被声明, 那么就打印$ERR_MSG;否则其值为 $var ${var:?ERR_MSG} 如果var没被设置, 那么就打印$ERR_MSG;否则其值为 $var ${!varprefix*} […]

Read More

简述systemd的新特性及unit常见类型分析

简述systemd的新特性及unit常见类型分析 systemd由来 Linux一直以来采用init进程但是init有两个缺点: 1、启动时间长。Init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。(这也是CentOS5的主要特征) 2、启动脚本复杂。Init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这使得脚本变得很长而且复杂。 Init:CentOS5: Sys init 是启动速度最慢的,串行启动过程,无论进程相互之间有无依赖关系。 CentOS6: Upstart init 相对启动速度快一点有所改进。有依赖的进程之间依次启动而其他与之没有依赖关系的则并行同步启动。 CentOS7: Systemd 与以上都不同。所有进程无论有无依赖关系则都是并行启动(当然很多时候进程没有真正启动而是只有一个信号或者说是标记而已,在真正利用的时候才会真正启动)。 systemd新特性 系统引导时实现服务并行启动; 按需激活进程; 系统状态快照; 基于依赖关系定义服务控制逻辑; unit Systemd可以管理系统中所有资源。不同的资源统称为unit(单位)。Unit表示不同类型的systemd对象,通过配置文件进程标识和配置;文件中主要包含了系统服务、监听socket、保存的系统快照以及其它与init相关的信息。 unit配置文件 /usr/lib/systemd/system /run/systemd/system /etc/systemd/system unit类型Unit一共分为12种。Sysstemctl –t help 查看unit类型,常见类型如下: Service unit:文件扩展名为.service,用于定义系统服务; Target unit:文件扩展为.target,用于模拟实现“运行级别”; Device unit: .device,用于定义内核识别的设备; Mount unit: […]

Read More

bash tricks: no alias, in source, …

BASH: \ls 前缀\的目的是避免alias替换,使用命令的原生目标来执行。当 alias ls=’ls –color’ 时,ls的输出结果是带高亮色的,\ls则避免了alias替换,输出结果没有高亮色。   BASH:函数名 function test_func() { echo “Current $FUNCNAME, \$FUNCNAME => (${FUNCNAME[@]})” another_func echo “Current $FUNCNAME, \$FUNCNAME => (${FUNCNAME[@]})” } $FUNCNAME是一个数组,包含倒序的函数名调用栈。例如“(child_func parent_func main_entry main)”,其中main_entry是首个函数调用入口,然后依次嵌套调用函数 parent_func 和 child_func,而main是一个伪函数名,它表示整个脚本文件。   BASH:避免多次source BASH自身检测SOURCE状态 使用一个环境变量来标识已经source过了 _sourced_=”__sourced_$$__” echo “Flag […]

Read More

Bash auto-completion

BASH 自动完成     AWS EC2 中,安装 bash-completion 软件包: yum install -y –enablerepo=epel bash-completion 在原生状态下,/etc/bash-completion.d是有效可用的,但增加自定义完成函数到这个文件夹中并不能获得自动完成效果,这通常是由于默认状态下只启用了部分自动完成特性,简单地安装bash-completion软件包则可以激活全部自动完成特性,而且附带了大量系统命令 的自动补全函数。   upstart命令的自动补全。 在EC2中,自定义的 upstart 服务无法被自动补全,也就是说,输入了 start 之后,TAB无法列举出可用的 upstart services清单。然而在非EC2环境中,例如自行安装Ubuntu 14/15/16发行版后upstart的自动补全功能是有效的。 为此,在EC2中则需要添加自定义补全脚本到 /etc/bash-completion.d/中,并logout & login以使能它(前提是已经安装了 bash-completion软件包)。   自定义Mac Bash补全和高亮显示 https://datahunter.org/bash-completion https://www.cyberciti.biz/faq/fedora-redhat-scientific-linuxenable-bash-completion/ bash-completion 自动补全功能增强 编写 Bash […]

Read More

bash tricks: 变量及其生存周期

本想讲述的清楚一点,然而发觉不够耐心,只好简单顺序地描述一下了 Bash 变量及其作用域 可以在bash脚本中定义变量。也可以在命令行交互过程中使用变量。在这些情况下,变量的定义方式都是相同的: A=1 echo $A 变量在定义之后一直有效,除非你取消它: A= unset A A= 可以为变量赋以空值。而 unset A 会完全取消该变量的存在性。 如果有必要,你可以使用 export 关键字来导出变量到环境变量中。 对于每一个shell实例来说,环境变量池是该shell实例的一个附着的空间,你可以丢入一堆变量。在一个shell中你可以执行多个shell脚本文件,对其中的每个脚本文件的执行实例来说,都有一个环境变量池的副本从当前shell实例复制而来,所以你在一个脚本文件中 export 某个变量A,那么A就被放入了该脚本文件实例的附着的环境变量池副本中。这个道理也适用于子shell的情况,因为调用执行一个脚本文件时就相当于fork了一个新的子shell实例,该新实例分享了当前shell实例的变量池的副本,因此在子shell中对变量的修改不会传递到父shell中。 那么,使用export有什么用处呢?我们知道,在当前shell环境下,执行一个脚本文件后,其中的变量会无效;source一个脚本的话,变量会继续可用。不过接着进行下一步,假设我们source了一个脚本文件使得变量A可用,然后进一步执行第二个脚本文件,这时在第二个脚本文件中A会是无效的,原因就在于第一步的变量A只是在当前shell环境中可用,但并不在当前的环境变量中,因此执行新脚本时A不会随着环境变量池一同被副本给新脚本。请注意,这时候就是export有用的时候了。 #!/bin/bash A=1 source A3.sh    # A3.sh 有 A=3 语句 echo $A  # 会显示 3 ./echoA.sh  # […]

Read More

bash rename,批量重命名就靠它了

bash中重命名文件一般是使用内置命令mv来完成的。mv的本质含义是移动一个文件,在bash中使用它则无须在文件系统中查找命令文件。 然而mv的语法受到很多限制,如果你需要重命名一批文件的话,它就不合适了。 幸运的是还有 rename 这条命令,而且在绝大多数 linux 发行版中,rename都是存在的并且表现一致。 rename 批量重命名可以使用 rename 命令,这个命令允许你使用正则式完成一堆文件名的策略性重命名操作。 rename的语法如下: Usage: rename [ -h|-m|-V ] [ -v ] [ -n ] [ -f ] [ -e|-E *perlexpr*]*|*perlexpr* [ *files* ] Options: -v, -verbose Verbose: print names of files […]

Read More

ops-toolset history 1

几年前在公司开发了一整套运维服务器脚本工具集,命名为 xxx OPS Toolset。 记得当年更迭了N多个版本之后,才最终成型,因为bash的编程能力在结构化组织上还是有限的,所以那时候也是下了功夫的。 现在公司的服务器群全部迁离了阿里云,这套工具集也顺应变化更新了若干次,最主要的变化是现在更通用了,不限于哪个公有云,几乎都能自适应。当然,新的版本乃至旧的版本目前还不能放出来;不过旧版本的截图,昨夜整理时发现,倒是可以post出来,也是对几年前工作的一个小小的回顾吧。 至于说框架结构,实际上我还是整理了两套的,分别是: bash-framework: https://github.com/hedzr/bash-framework bash.sh: https://github.com/hedzr/bash.sh bash-framwork 呢,基本上是 ops toolset 的框架结构,也可以说是一个最小集合的Bash脚本编程框架,主要面向 DevOps 管理任务。 因此,默认的函数集合中包含了像 package-install, is_package_installed, if_ubuntu, if_centos, is_root 这类辅助函数。 不过,由于安装主站的vps不稳定,所以它的分发大约是有问题的,需要的朋友自己去拉源码再自行改造适用了。 至于 bash.sh 就微型得多了。 bash.sh主要是面向单文件开发。bash-framwork主要是面向整套脚本集合的组织、开发,适合组织成系列的大型脚本集合。反过来说 bash.sh 则是一个快速的起点,例如你需要在建设rabbitmq集群方面做一套子命令集合,那就可以直接clone bash.sh的主文件改成 rmq-ctl,然后直接编写bash函数到这个文件中,就可以使用像 rmq-ctl init 3 nodes 这样的命令了。所以像 sdkman 那样的命令套装,用 bash.sh 可以很容易实现。 […]

Read More

How to change committer name of multiple commits in git?

当一个git repo没有被推向远程服务器时,我们有机会能够改变本地的全部提交者信息。如果你使用多个id分别做不同的工作的话,这个方法或许是有用的。 按照 Stack Overflow 上 How to change the author and committer name and e-mail of multiple commits in Git? 的方法,下面有一个 bash 脚本,你可以命名为 git-apply-xxx.sh 并发到 /usr/local/bin 中去,然后用 BAD_NAME=my-wrong-name NAME=my-right-name EMAIL=my-right-email@xxx git-apply-xxx.sh 来批量修改所有的提交的作者到新的id上面去。 #!/bin/sh git filter-branch –env-filter ” OLD_EMAIL=${BAD_NAME:-your-old-email@example.com} CORRECT_NAME=${NAME:-Your Name} CORRECT_EMAIL=${EMAIL:-your-correct-email@example.com} if [ […]

Read More

通过堡垒机透明连接到云中任意内网主机

通过堡垒机透明连接到云中任意内网主机,且自由切换到其他主机。 适合于各种公有云环境。   前置条件 你的SSH证书在每一台主机上都有相同的账户名以及控制台登录授权。 这一点其实不怎么容易,比较可行的方法有: 通过自定义镜像预先做好账户名,并用该镜像开机 通过一套ops脚本集,在每台主机上执行一次特定子功能以便建立相同的账户名以及授权 通过ansible或类似的部署工具,执行专用脚本以便建立账户名 关于前置条件的实现,不在本文的讨论范畴,因此这里不再展开细节了。   本机 你的工作主机需要有一点准备:请修改 ~/.bashrc 追加如下语句: ssh -add -K ~/.ssh/id_rsa alias ssh=’ssh -A’ 以上我们假定你的主力SSH证书就是当前账户的缺省证书,否则你需要指定正确的证书路径。 上面的语句将会在SSH会话中携带你的证书到任意位置,当然你也并不必担心证书的泄露问题,你的证书只会存在在内存中。   堡垒机 假定前置条件是满足的,例如已经在某个新的VPC中准备好了自定义镜像,并且新开第一台主机作为堡垒机,并且主机名命名为 cx1ops00,那么 ssh cx1ops00 应该能顺利登录到该主机。 堡垒机需要开启SSH转发,可以修改堡垒机的 /etc/ssh/ssh_config 加入: Host cc*     ForwardAgent yes […]

Read More

运维账户免密sudo

因为背不住,也不想转到脚本那边去check源码,所以快速笔记一下: groupadd -g222 devops groupadd -g225 admin groupadd -g333 hzadmin cat >/etc/sudoers.d/hzadmin<<EEE %devops  ALL=(ALL) NOPASSWD:ALL %hzadmin  ALL=(ALL) NOPASSWD:ALL %admin  ALL=(root) NOPASSWD: /bin/systemctl EEE usermod -aG hzadmin,devops me sudo 命令免密的关键,在于 NOPASSWD:ALL。如果想要给特定账户而不是账户组授予特定权限,则可以用: someone ALL=(root) NOPASSWD: /bin/systemctl 这个示例可以给账户someone授予执行systemctl的权利。类似的journalctl也可以这么做。 不过,也可以选择将账户加入到某个特定组,例如adm组、或者www-data组,的方式来使其具有特别权利。      

Read More