在 Linux 中打扮你的冬季 Bash 提示符

你的 Linux 终端可能支持 Unicode,那么为何不利用它在提示符中添加季节性的图标呢?

欢迎再次来到 Linux 命令行玩具日历的另一篇。如果这是你第一次访问该系列,你甚至可能会问自己什么是命令行玩具?我们对此比较随意:它会是终端上有任何有趣的消遣,对于任何节日主题相关的还有额外的加分。

也许你以前见过其中的一些,也许你没有。不管怎样,我们希望你玩得开心。

今天的玩具非常简单:它是你的 Bash 提示符。你的 Bash 提示符?是的!我们还有几个星期的假期可以盯着它看,在北半球冬天还会再多几周,所以为什么不玩玩它。

目前你的 Bash 提示符号可能是一个简单的美元符号( $),或者更有可能是一个更长的东西。如果你不确定你的 Bash 提示符是什么,你可以在环境变量 $PS1 中找到它。要查看它,请输入:

echo $PS1

对于我而言,它返回:

[u@h W]$

uhW 分别是用户名、主机名和工作目录的特殊字符。你还可以使用其他一些符号。为了帮助构建你的 Bash 提示符,你可以使用 EzPrompt,这是一个 PS1 配置的在线生成器,它包含了许多选项,包括日期和时间、Git 状态等。

你可能还有其他变量来组成 Bash 提示符。对我来说,$PS2 包含了我命令提示符的结束括号。有关详细信息,请参阅 这篇文章。

要更改提示符,只需在终端中设置环境变量,如下所示:

$ PS1='u is cold: '
jehb is cold:

要永久设置它,请使用你喜欢的文本编辑器将相同的代码添加到 /etc/bashrc 中。

那么这些与冬季化有什么关系呢?好吧,你很有可能有现代一下的机器,你的终端支持 Unicode,所以你不仅限于标准的 ASCII 字符集。你可以使用任何符合 Unicode 规范的 emoji,包括雪花 ❄、雪人 ☃ 或一对滑雪板。你有很多冬季 emoji 可供选择。

  • 圣诞树
  • 外套
  • 鹿手套
  • 圣诞夫人
  • 圣诞老人
  • 围巾
  • 滑雪者
  • 滑雪板
  • 雪花
  • 雪人
  • 没有雪的雪人
  • 包装好的礼物

选择你最喜欢的,享受冬天的欢乐。有趣的事实:现代文件系统也支持文件名中的 Unicode 字符,这意味着技术上你可以将你下个程序命名为 ❄❄❄❄❄.py。只是说说,不要这么做。

解决Linux环境下执行脚本时报错:/bin/bash^M: 坏的解释器: 没有那个文件或目录

一、问题描述

我在Windows 10 系统下编辑了一个发送消息到企业微信的shell脚本文件,然后copy到了远程的Linux服务器,当运行的时候报错了。如下所示:

未分类

root@ubuntu116:/data/gitlabData/auto_back_shell# ./qiyewechat-notifier.sh 
-bash: ./qiyewechat-notifier.sh: /bin/bash^M: 坏的解释器: 没有那个文件或目录
root@ubuntu116:/data/gitlabData/auto_back_shell# 

二、错误原因

这个文件在Windows 下编辑过,在Windows下每一行结尾是nr,而Linux下则是n,所以才会有 多出来的r。

三、修改错误

使用指令sed -i 's/r$//' xxxxxxx.sh,上面的指令会把 xxxxxxx.sh 中的r 替换成空白!
实操一下:

未分类

root@ubuntu116:/data/gitlabData/auto_back_shell# sed -i 's/r$//' qiyewechat-notifier.sh 
您在 /var/mail/root 中有新邮件
root@ubuntu116:/data/gitlabData/auto_back_shell# ./qiyewechat-notifier.sh -h 
./qiyewechat-notifier.sh: 非法选项 -- h
Usage:
  qiyewechat.sh [-u USER] [-t TITLE] [-c CONTENT] [-d DETAIL] [-p PICTURE]
Description:
    USER, 用户.
    TITLE, 标题.
    CONTENT, 内容.
    DETAIL, 细节.
    PICTURE, 图片.
root@ubuntu116:/data/gitlabData/auto_back_shell# 

如上所示,执行了下面的脚本之后,

sed -i 's/r$//' qiyewechat-notifier.sh

qiyewechat-notifier.sh就可以正常运行了!

四、附录

qiyewechat-notifier.sh的部分代码如下所示:

未分类

#!/bin/bash

#用法提示
usage() {
    echo "Usage:"
    echo "  qiyewechat.sh [-u USER] [-t TITLE] [-c CONTENT] [-d DETAIL] [-p PICTURE]"
    echo "Description:"
    echo "    USER, 用户."
    echo "    TITLE, 标题."
    echo "    CONTENT, 内容."
    echo "    DETAIL, 细节."
    echo "    PICTURE, 图片."
    exit -1
}


# 获取脚本执行时的选项
while getopts u:t:c:d:p: option
do
   case "${option}"  in
                u) USER=${OPTARG};;
                t) TITLE=${OPTARG};;
                c) CONTENT=${OPTARG};;
                d) DETAIL=${OPTARG};;
                p) PICTURE=${OPTARG};;
                h) usage;;
                ?) usage;;
   esac
   echo $option
   echo $OPTARG

done

你所不了解的 Bash:关于 Bash 数组的介绍

进入这个古怪而神奇的 Bash 数组的世界。

尽管软件工程师常常使用命令行来进行各种开发,但命令行中的数组似乎总是一个模糊的东西(虽然不像正则操作符 =~ 那么复杂隐晦)。除开隐晦和有疑问的语法,Bash 数组其实是非常有用的。

稍等,这是为什么?

写 Bash 相关的东西很难,但如果是写一篇像手册那样注重怪异语法的文章,就会非常简单。不过请放心,这篇文章的目的就是让你不用去读该死的使用手册。

真实(通常是有用的)示例

为了这个目的,想象一下真实世界的场景以及 Bash 是怎么帮忙的:你正在公司里面主导一个新工作,评估并优化内部数据管线的运行时间。首先,你要做个参数扫描分析来评估管线使用线程的状况。简单起见,我们把这个管道当作一个编译好的 C++ 黑盒子,这里面我们能够调整的唯一的参数是用于处理数据的线程数量: ./pipeline --threads 4

基础

我们首先要做的事是定义一个数组,用来容纳我们想要测试的 –threads 参数:

allThreads=(1 2 4 8 16 32 64 128)

本例中,所有元素都是数字,但参数并不一定是数字,Bash 中的数组可以容纳数字和字符串,比如 myArray=(1 2 “three” 4 “five”) 就是个有效的表达式。就像 Bash 中其它的变量一样,确保赋值符号两边没有空格。否则 Bash 将会把变量名当作程序来执行,把 = 当作程序的第一个参数。

现在我们初始化了数组,让我们解析它其中的一些元素。仅仅输入 echo $allThreads ,你能发现,它只会输出第一个元素。

要理解这个产生的原因,需要回到上一步,回顾我们一般是怎么在 Bash 中输出变量。考虑以下场景:

type="article"
echo "Found 42 $type"

假如我们得到的变量 $type 是一个单词,我们想要添加在句子结尾一个 s。我们无法直接把 s 加到 $type 里面,因为这会把它变成另一个变量,$types。尽管我们可以利用像 echo “Found 42 “$type”s” 这样的代码形变,但解决这个问题的最好方法是用一个花括号:echo “Found 42 ${type}s”,这让我们能够告诉 Bash 变量名的起止位置(有趣的是,JavaScript/ES6 在 template literals 中注入变量和表达式的语法和这里是一样的)

事实上,尽管 Bash 变量一般不用花括号,但在数组中需要用到花括号。这反而允许我们指定要访问的索引,例如 echo ${allThreads[1]} 返回的是数组中的第二个元素。如果不写花括号,比如 echo $allThreads[1],会导致 Bash 把 [1] 当作字符串然后输出。

是的,Bash 数组的语法很怪,但是至少他们是从 0 开始索引的,不像有些语言(说的就是你,R 语言)。

遍历数组

上面的例子中我们直接用整数作为数组的索引,我们现在考虑两种其他情况:第一,如果想要数组中的第 $i 个元素,这里 $i 是一个代表索引的变量,我们可以这样 echo ${allThreads[$i]} 解析这个元素。第二,要输出一个数组的所有元素,我们把数字索引换成 @ 符号(你可以把 @ 当作表示 all 的符号):echo ${allThreads[@]}。

遍历数组元素

记住上面讲过的,我们遍历 $allThreads 数组,把每个值当作 –threads 参数启动管线:

for t in ${allThreads[@]}; do
  ./pipeline --threads $t
done

遍历数组索引

接下来,考虑一个稍稍不同的方法。不遍历所有的数组元素,我们可以遍历所有的索引:

for i in ${!allThreads[@]}; do
  ./pipeline --threads ${allThreads[$i]}
done

一步一步看:如之前所见,${allThreads[@]} 表示数组中的所有元素。前面加了个感叹号,变成 ${!allThreads[@]},这会返回数组索引列表(这里是 0 到 7)。换句话说。for 循环就遍历所有的索引 $i 并从 $allThreads 中读取第 $i 个元素,当作 –threads 选项的参数。

这看上去很辣眼睛,你可能奇怪为什么我要一开始就讲这个。这是因为有时候在循环中需要同时获得索引和对应的值,例如,如果你想要忽视数组中的第一个元素,使用索引可以避免额外创建在循环中累加的变量。

填充数组

到目前为止,我们已经能够用给定的 –threads 选项启动管线了。现在假设按秒计时的运行时间输出到管线。我们想要捕捉每个迭代的输出,然后把它保存在另一个数组中,因此我们最终可以随心所欲的操作它。

一些有用的语法

在深入代码前,我们要多介绍一些语法。首先,我们要能解析 Bash 命令的输出。用这个语法可以做到:output=$( ./my_script.sh ),这会把命令的输出存储到变量 $output 中。

我们需要的第二个语法是如何把我们刚刚解析的值添加到数组中。完成这个任务的语法看起来很熟悉:

myArray+=( "newElement1" "newElement2" )

参数扫描

万事具备,执行参数扫描的脚步如下:

allThreads=(1 2 4 8 16 32 64 128)
allRuntimes=()
for t in ${allThreads[@]}; do
  runtime=$(./pipeline --threads $t)
  allRuntimes+=( $runtime )
done

就是这个了!

还有什么能做的?

这篇文章中,我们讲过使用数组进行参数扫描的场景。我敢保证有很多理由要使用 Bash 数组,这里就有两个例子:

日志警告

本场景中,把应用分成几个模块,每一个都有它自己的日志文件。我们可以编写一个 cron 任务脚本,当某个模块中出现问题标志时向特定的人发送邮件:

# 日志列表,发生问题时应该通知的人
logPaths=("api.log" "auth.log" "jenkins.log" "data.log")
logEmails=("jay@email" "emma@email" "jon@email" "sophia@email")
# 在每个日志中查找问题标志
for i in ${!logPaths[@]};
do
  log=${logPaths[$i]}
  stakeholder=${logEmails[$i]}
  numErrors=$( tail -n 100 "$log" | grep "ERROR" | wc -l )
  # 如果近期发现超过 5 个错误,就警告负责人
  if [[ "$numErrors" -gt 5 ]];
  then
    emailRecipient="$stakeholder"
    emailSubject="WARNING: ${log} showing unusual levels of errors"
    emailBody="${numErrors} errors found in log ${log}"
    echo "$emailBody" | mailx -s "$emailSubject" "$emailRecipient"
  fi
done

API 查询

如果你想要生成一些分析数据,分析你的 Medium 帖子中用户评论最多的。由于我们无法直接访问数据库,SQL 不在我们考虑范围,但我们可以用 API!

为了避免陷入关于 API 授权和令牌的冗长讨论,我们将会使用 JSONPlaceholder,这是一个面向公众的测试服务 API。一旦我们查询每个帖子,解析出每个评论者的邮箱,我们就可以把这些邮箱添加到我们的结果数组里:

endpoint="https://jsonplaceholder.typicode.com/comments"
allEmails=()
# 查询前 10 个帖子
for postId in {1..10};
do
  # 执行 API 调用,获取该帖子评论者的邮箱
  response=$(curl "${endpoint}?postId=${postId}")

  # 使用 jq 把 JSON 响应解析成数组
  allEmails+=( $( jq '.[].email' <<< "$response" ) )
done

注意这里我是用 jq 工具 从命令行里解析 JSON 数据。关于 jq 的语法超出了本文的范围,但我强烈建议你了解它。

你可能已经想到,使用 Bash 数组在数不胜数的场景中很有帮助,我希望这篇文章中的示例可以给你思维的启发。如果你从自己的工作中找到其它的例子想要分享出来,请在帖子下方评论。

请等等,还有很多东西!

由于我们在本文讲了很多数组语法,这里是关于我们讲到内容的总结,包含一些还没讲到的高级技巧:

未分类

最后一点思考

正如我们所见,Bash 数组的语法很奇怪,但我希望这篇文章让你相信它们很有用。只要你理解了这些语法,你会发现以后会经常使用 Bash 数组。

Bash 还是 Python?

问题来了:什么时候该用 Bash 数组而不是其他的脚本语法,比如 Python?

对我而言,完全取决于需求——如果你可以只需要调用命令行工具就能立马解决问题,你也可以用 Bash。但有些时候,当你的脚本属于一个更大的 Python 项目时,你也可以用 Python。

比如,我们可以用 Python 来实现参数扫描,但我们只用编写一个 Bash 的包装:

import subprocess
all_threads = [1, 2, 4, 8, 16, 32, 64, 128]
all_runtimes = []
# 用不同的线程数字启动管线
for t in all_threads:
  cmd = './pipeline --threads {}'.format(t)
  # 使用子线程模块获得返回的输出
  p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
  output = p.communicate()[0]
  all_runtimes.append(output)

由于本例中没法避免使用命令行,所以可以优先使用 Bash。

羞耻的宣传时间

如果你喜欢这篇文章,这里还有很多类似的文章! 在此注册,加入 OSCON (https://conferences.oreilly.com/oscon/oscon-or) ,2018 年 7 月 17 号我会在这做一个主题为 你所不了解的 Bash 的在线编码研讨会。没有幻灯片,不需要门票,只有你和我在命令行里面敲代码,探索 Bash 中的奇妙世界。

如何在Linux中轻松修正拼写错误的Bash命令?

未分类

我知道你可以按下向上箭头来调出你运行过的命令,然后使用左/右键移动到拼写错误的单词,并更正拼写错误的单词,最后按回车键再次运行它,对吗?可是等等。还有一种更简单的方法可以纠正 GNU/Linux 中拼写错误的 Bash 命令。这个教程解释了如何做到这一点。请继续阅读。

在 Linux 中纠正拼写错误的 Bash 命令

你有没有运行过类似于下面的错误输入命令?

$ unme -r
bash: unme: command not found

你注意到了吗?上面的命令中有一个错误。我在 uname 命令缺少了字母 a。

我在很多时候犯过这种愚蠢的错误。在我知道这个技巧之前,我习惯按下向上箭头来调出命令,并转到命令中拼写错误的单词,纠正拼写错误,然后按回车键再次运行该命令。但相信我。下面的技巧非常易于纠正你刚刚运行的命令中的任何拼写错误。

要轻松更正上述拼写错误的命令,只需运行:

$ ^nm^nam^

这会将 uname 命令中将 nm 替换为 nam。很酷,是吗?它不仅纠正错别字,而且还能运行命令。查看下面的截图。

未分类

当你在命令中输入错字时使用这个技巧。请注意,它仅适用于 Bash shell。

额外提示:

你有没有想过在使用 cd 命令时如何自动纠正拼写错误?没有么?没关系!下面的技巧将解释如何做到这一点。

这个技巧只能纠正使用 cd 命令时的拼写错误。

比如说,你想使用命令切换到 Downloads 目录:

$ cd Donloads
bash: cd: Donloads: No such file or directory

哎呀!没有名称为 Donloads 的文件或目录。是的,正确的名称是 Downloads。上面的命令中缺少 w。
要解决此问题并在使用 cd 命令时自动更正错误,请编辑你的 .bashrc 文件:

$ vi ~/.bashrc

最后添加以下行。

[...]
shopt -s cdspell

输入 :wq 保存并退出文件。

最后,运行以下命令更新更改。

$ source ~/.bashrc

现在,如果在使用 cd 命令时路径中存在任何拼写错误,它将自动更正并进入正确的目录。

未分类

正如你在上面的命令中看到的那样,我故意输错(Donloads 而不是 Downloads),但 Bash 自动检测到正确的目录名并 cd 进入它。

Fish 和 Zsh shell 内置的此功能。所以,如果你使用的是它们,那么你不需要这个技巧。

然而,这个技巧有一些局限性。它只适用于使用正确的大小写。在上面的例子中,如果你输入的是 cd donloads 而不是 cd Donloads,它将无法识别正确的路径。另外,如果路径中缺少多个字母,它也不起作用。

Linux终端前缀变成-bash-4.2#解决办法

这个问题困扰了我很久,每次登陆终端提示就是这样子:

Last login: Fri Jan 19 15:57:15 2018 from 
Welcome to JCLOUD Elastic Compute Service
-bash-4.2#

后来以为是软件环境问题,找到了个解决办法:

终端输入:PS1="[root@localhost ~]"

之后看起来是解决了这个问题,但是一直是这样子的提示,进出目录该有的提示都没有,就是个摆设。

后来找到了正确的解决方法。

这个问题出现的原因是.bashrc文件被破坏,导致里面没有该有的内容
那是什么内容呢?就是这个:

PS1='[u@h W]$ '

因为我把rm改造为mv之后,没有加上这个代码,导致读取不到,所以就显示bash-4.2,把这个代码加入.bashrc之后,source .bashrc即可恢复。

上代码示例:

PS1='[u@h W]$ '>>.bashrc
source .bashrc

这样就解决了这个问题,希望对出现此问题的有帮助。

解释下shell下的bash中的test记忆

解决问题

  • test有几种写法
  • [ -f 1.txt ] 为什么在[]前后必须有空格

写法

if [ -f 1.txt ];then echo "hello";fi

if [ -f 1.txt ];then
    echo "hello"
fi

if [ -f 1.txt ];
then
    echo "hello"
fi

if [ -f 1.txt ]
then echo "hello"
fi

if [ -f 1.txt]
then
    echo "hello"
fi

总结

  • [ -f 1.txt ] ‘[‘是命令名 ’-f 1.txt ]’是参数,参数是用空格分割的,这是一个命令
  • if then后都是跟的命令
  • ;和回车都可以分割命令,多个命令在一行要用;分割

通过ssh会话执行bash别名

SSH 客户端 (ssh) 是一个登录远程服务器并在远程系统上执行 shell 命令的 Linux/Unix 命令。它被设计用来在两个非信任的机器上通过不安全的网络(比如互联网)提供安全的加密通讯。

未分类

我在远程主机上上设置过一个叫做 file_repl 的 bash 别名 。当我使用 ssh 命令登录远程主机后,可以很正常的使用这个别名。然而这个 bash 别名却无法通过 ssh 来运行,像这样:

$ ssh [email protected] file_repl
bash:file_repl:command not found

我要怎样做才能通过 ssh 命令运行 bash 别名呢?

SSH 客户端 (ssh) 是一个登录远程服务器并在远程系统上执行 shell 命令的 Linux/Unix 命令。它被设计用来在两个非信任的机器上通过不安全的网络(比如互联网)提供安全的加密通讯。

如何用 ssh 客户端执行命令

通过 ssh 运行 free 命令或 date 命令 可以这样做:

$ ssh [email protected] date

结果为:

Tue Dec 26 09:02:50 UTC 2017

或者:

$ ssh [email protected] free -h

结果为:

 total used free shared buff/cache available
Mem:2.0G 428M 138M 145M 1.4G 1.1G
Swap:0B 0B 0B

理解 bash shell 以及命令的类型

bash shell 共有下面几类命令:

  • 别名,比如 ll
  • 关键字,比如 if
  • 函数 (用户自定义函数,比如 genpasswd)
  • 内置命令,比如 pwd
  • 外部文件,比如 /bin/date

type 命令 和 command 命令 可以用来查看命令类型:

$ type -a date
date is /bin/date
$ type -a free
free is /usr/bin/free
$ command -V pwd
pwd is a shell builtin
$ type -a file_repl
is aliased to `sudo -i /shared/takes/master.replication'

date 和 free 都是外部命令,而 file_repl 是 sudo -i /shared/takes/master.replication 的别名。你不能直接执行像 file_repl 这样的别名:

$ ssh user@remote file_repl

在 Unix 系统上无法直接通过 ssh 客户端执行 bash 别名
要解决这个问题可以用下面方法运行 ssh 命令:

$ ssh -t user@remote /bin/bash -ic 'your-alias-here'
$ ssh -t user@remote /bin/bash -ic 'file_repl'

ssh 命令选项:

  • -t:强制分配伪终端。可以用来在远程机器上执行任意的 基于屏幕的程序,有时这非常有用。当使用 -t 时你可能会收到一个类似 “bash: cannot set terminal process group (-1): Inappropriate ioctl for device. bash: no job control in this shell .” 的错误。

bash shell 的选项:

  • -i:运行交互 shell,这样 shell 才能运行 bash 别名。
  • -c:要执行的命令取之于第一个非选项参数的命令字符串。若在命令字符串后面还有其他参数,这些参数会作为位置参数传递给命令,参数从 $0 开始。

总之,要运行一个名叫 ll 的 bash 别名,可以运行下面命令:

$ ssh -t [email protected] -ic 'll'

结果为:

未分类

Running bash aliases over ssh based session when using Unix or Linux ssh cli

下面是我的一个 shell 脚本的例子:

#!/bin/bash
I="tags.deleted.410"
O="/tmp/https.www.cyberciti.biz.410.url.conf"
box="[email protected]"
[!-f "$I" ] && { echo "$I file not found。"; exit 10; }
>$O
cat "$I" | sort | uniq | while read -r u
do
    uu="${u##https://www.cyberciti.biz}"
    echo "~^$uu 1;" >>"${O}"
done
echo "Config file created at ${O} and now updating remote nginx config file"
scp "${O}" ${box}:/tmp/
ssh ${box} /usr/bin/lxc file push /tmp/https.www.cyberciti.biz.410.url.conf nginx-container/etc/nginx/
ssh -t ${box} /bin/bash -ic 'push_config_job'

相关资料

更多信息请输入下面命令查看 OpenSSH 客户端 和 bash 的 man 帮助 :

$ man ssh
$ man bash
$ help type
$ help command 

30个方便的bash shell别名

bash 别名alias只不过是指向命令的快捷方式而已。alias 命令允许用户只输入一个单词就运行任意一个命令或一组命令(包括命令选项和文件名)。执行 alias 命令会显示一个所有已定义别名的列表。你可以在 ~/.bashrc 文件中自定义别名。使用别名可以在命令行中减少输入的时间,使工作更流畅,同时增加生产率。

本文通过 30 个 bash shell 别名的实际案例演示了如何创建和使用别名。

bash alias 的那些事

bash shell 中的 alias 命令的语法是这样的:

alias [alias-name[=string]...]

如何列出 bash 别名

输入下面的 alias 命令:

alias

结果为:

alias ..='cd ..'
alias amazonbackup='s3backup'
alias apt-get='sudo apt-get'
...

alias 命令默认会列出当前用户定义好的别名。

如何定义或者创建一个 bash shell 别名

使用下面语法 创建别名:

alias name =value
alias name = 'command'
alias name = 'command arg1 arg2' 
alias name = '/path/to/script' 
alias name = '/path/to/script.pl arg1'

举个例子,输入下面命令并回车就会为常用的 clear(清除屏幕)命令创建一个别名 c:

alias c = 'clear'

然后输入字母 c 而不是 clear 后回车就会清除屏幕了:

c

如何临时性地禁用 bash 别名

下面语法可以临时性地禁用别名:

## path/to/full/command
/usr/bin/clear
## call alias with a backslash ##
c
## use /bin/ls command and avoid ls alias ##
command ls

如何删除 bash 别名

使用 unalias 命令来删除别名。其语法为:

unalias aliasname
unalias foo

例如,删除我们之前创建的别名 c:

unalias c

你还需要用文本编辑器删掉 ~/.bashrc 文件 中的别名定义(参见下一部分内容)。

如何让 bash shell 别名永久生效

别名 c 在当前登录会话中依然有效。但当你登出或重启系统后,别名 c 就没有了。为了防止出现这个问题,将别名定义写入 ~/.bashrc file 中,输入:

vi ~/.bashrc

输入下行内容让别名 c 对当前用户永久有效:

alias c = 'clear'

保存并关闭文件就行了。系统级的别名(也就是对所有用户都生效的别名)可以放在 /etc/bashrc 文件中。请注意,alias 命令内建于各种 shell 中,包括 ksh,tcsh/csh,ash,bash 以及其他 shell。

关于特权权限判断

可以将下面代码加入 ~/.bashrc:

# if user is not root, pass all commands via sudo #
if [ $UID -ne 0 ]; then
    alias reboot='sudo reboot'
    alias update='sudo apt-get upgrade'
fi

定义与操作系统类型相关的别名

可以将下面代码加入 ~/.bashrc 使用 case 语句:

### Get os name via uname ###
_myos="$(uname)"

### add alias as per os using $_myos ###
case $_myos in
   Linux) alias foo='/path/to/linux/bin/foo';;
   FreeBSD|OpenBSD) alias foo='/path/to/bsd/bin/foo' ;;
   SunOS) alias foo='/path/to/sunos/bin/foo' ;;
   *) ;;
esac

30 个 bash shell 别名的案例

你可以定义各种类型的别名来节省时间并提高生产率。

1:控制 ls 命令的输出

ls 命令列出目录中的内容 而你可以对输出进行着色:

## Colorize the ls output ##
alias ls = 'ls --color=auto'

## Use a long listing format ##
alias ll = 'ls -la'

## Show hidden files ##
alias l.= 'ls -d . .. .git .gitignore .gitmodules .travis.yml --color=auto'

2:控制 cd 命令的行为

## get rid of command not found ##
alias cd..= 'cd ..'

## a quick way to get out of current directory ##
alias ..= 'cd ..'
alias ...= 'cd ../../../'
alias ....= 'cd ../../../../'
alias .....= 'cd ../../../../'
alias .4= 'cd ../../../../'
alias .5= 'cd ../../../../..'

3:控制 grep 命令的输出

grep 命令是一个用于在纯文本文件中搜索匹配正则表达式的行的命令行工具:

## Colorize the grep command output for ease of use (good for log files)##
alias grep = 'grep --color=auto'
alias egrep = 'egrep --color=auto'
alias fgrep = 'fgrep --color=auto'

4:让计算器默认开启 math 库

alias bc = 'bc -l'

4:生成 sha1 数字签名

alias sha1 = 'openssl sha1'

5:自动创建父目录

mkdir 命令 用于创建目录:

alias mkdir = 'mkdir -pv'

6:为 diff 输出着色

你可以使用 diff 来一行行第比较文件 而一个名为 colordiff 的工具可以为 diff 输出着色:

# install colordiff package :)
alias diff = 'colordiff'

7:让 mount 命令的输出更漂亮,更方便人类阅读

alias mount = 'mount |column -t'

8:简化命令以节省时间

# handy short cuts #
alias h = 'history' 
alias j = 'jobs -l'

9:创建一系列新命令

alias path = 'echo -e ${PATH//:/\n}'
alias now = 'date +"%T"'
alias nowtime =now
alias nowdate = 'date +"%d-%m-%Y"'

10:设置 vim 为默认编辑器

alias vi = vim
alias svi = 'sudo vi'
alias vis = 'vim "+set si"'
alias edit = 'vim'

11:控制网络工具 ping 的输出

# Stop after sending count ECHO_REQUEST packets #
alias ping = 'ping -c 5'

# Do not wait interval 1 second, go fast #
alias fastping = 'ping -c 100 -s.2'

12:显示打开的端口

使用 netstat 命令 可以快速列出服务区中所有的 TCP/UDP 端口:

alias ports = 'netstat -tulanp'

13:唤醒休眠的服务器

Wake-on-LAN (WOL) 是一个以太网标准,可以通过网络消息来开启服务器。你可以使用下面别名来快速激活 nas 设备 以及服务器:

## replace mac with your actual server mac address #
alias wakeupnas01 = '/usr/bin/wakeonlan 00:11:32:11:15:FC'
alias wakeupnas02 = '/usr/bin/wakeonlan 00:11:32:11:15:FD'
alias wakeupnas03 = '/usr/bin/wakeonlan 00:11:32:11:15:FE'

14:控制防火墙 (iptables) 的输出

Netfilter 是一款 Linux 操作系统上的主机防火墙。它是 Linux 发行版中的一部分,且默认情况下是激活状态。这里列出了大多数 Liux 新手防护入侵者最常用的 iptables 方法。

## shortcut for iptables and pass it via sudo#
alias ipt = 'sudo /sbin/iptables'

# display all rules #
alias iptlist = 'sudo /sbin/iptables -L -n -v --line-numbers'
alias iptlistin = 'sudo /sbin/iptables -L INPUT -n -v --line-numbers'
alias iptlistout = 'sudo /sbin/iptables -L OUTPUT -n -v --line-numbers'
alias iptlistfw = 'sudo /sbin/iptables -L FORWARD -n -v --line-numbers'
alias firewall =iptlist

15:使用 curl 调试 web 服务器 / CDN 上的问题

# get web server headers #
alias header = 'curl -I'

# find out if remote server supports gzip / mod_deflate or not #
alias headerc = 'curl -I --compress'

16:增加安全性

# do not delete / or prompt if deleting more than 3 files at a time #
alias rm = 'rm -I --preserve-root'

# confirmation #
alias mv = 'mv -i'
alias cp = 'cp -i'
alias ln = 'ln -i' 

# Parenting changing perms on / #
alias chown = 'chown --preserve-root'
alias chmod = 'chmod --preserve-root'
alias chgrp = 'chgrp --preserve-root'

17:更新 Debian Linux 服务器

apt-get 命令 用于通过因特网安装软件包 (ftp 或 http)。你也可以一次性升级所有软件包:

# distro specific - Debian / Ubuntu and friends #
# install with apt-get
alias apt-get= "sudo apt-get"
alias updatey = "sudo apt-get --yes"

# update on one command
alias update = 'sudo apt-get update && sudo apt-get upgrade'

18:更新 RHEL / CentOS / Fedora Linux 服务器

yum 命令 是 RHEL / CentOS / Fedora Linux 以及其他基于这些发行版的 Linux 上的软件包管理工具:

## distrp specifc RHEL/CentOS ##
alias update = 'yum update'
alias updatey = 'yum -y update'

19:优化 sudo 和 su 命令

# become root #
alias root = 'sudo -i' 
alias su = 'sudo -i'

20:使用 sudo 执行 halt/reboot 命令

shutdown 命令 会让 Linux / Unix 系统关机:

# reboot / halt / poweroff
alias reboot = 'sudo /sbin/reboot'
alias poweroff = 'sudo /sbin/poweroff' 
alias halt = 'sudo /sbin/halt'
alias shutdown = 'sudo /sbin/shutdown'

21:控制 web 服务器

# also pass it via sudo so whoever is admin can reload it without calling you #
alias nginxreload = 'sudo /usr/local/nginx/sbin/nginx -s reload' 
alias nginxtest = 'sudo /usr/local/nginx/sbin/nginx -t'
alias lightyload = 'sudo /etc/init.d/lighttpd reload' 
alias lightytest = 'sudo /usr/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf -t'
alias httpdreload = 'sudo /usr/sbin/apachectl -k graceful' 
alias httpdtest = 'sudo /usr/sbin/apachectl -t && /usr/sbin/apachectl -t -D DUMP_VHOSTS'

22:与备份相关的别名

# if cron fails or if you want backup on demand just run these commands #
# again pass it via sudo so whoever is in admin group can start the job #
# Backup scripts #
alias backup = 'sudo /home/scripts/admin/scripts/backup/wrapper.backup.sh --type local --taget /raid1/backups' 
alias nasbackup = 'sudo /home/scripts/admin/scripts/backup/wrapper.backup.sh --type nas --target nas01'
alias s3backup = 'sudo /home/scripts/admin/scripts/backup/wrapper.backup.sh --type nas --target nas01 --auth /home/scripts/admin/.authdata/amazon.keys'
alias rsnapshothourly = 'sudo /home/scripts/admin/scripts/backup/wrapper.rsnapshot.sh --type remote --target nas03 --auth /home/scripts/admin/.authdata/ssh.keys --config /home/scripts/admin/scripts/backup/config/adsl.conf'
alias rsnapshotdaily = 'sudo /home/scripts/admin/scripts/backup/wrapper.rsnapshot.sh --type remote --target nas03 --auth /home/scripts/admin/.authdata/ssh.keys --config /home/scripts/admin/scripts/backup/config/adsl.conf'
alias rsnapshotweekly = 'sudo /home/scripts/admin/scripts/backup/wrapper.rsnapshot.sh --type remote --target nas03 --auth /home/scripts/admin/.authdata/ssh.keys --config /home/scripts/admin/scripts/backup/config/adsl.conf' 
alias rsnapshotmonthly = 'sudo /home/scripts/admin/scripts/backup/wrapper.rsnapshot.sh --type remote --target nas03 --auth /home/scripts/admin/.authdata/ssh.keys --config /home/scripts/admin/scripts/backup/config/adsl.conf' 
alias amazonbackup =s3backup

23:桌面应用相关的别名 – 按需播放的 avi/mp3 文件

## play video files in a current directory ##
# cd ~/Download/movie-name
# playavi or vlc
alias playavi = 'mplayer *.avi' 
alias vlc = 'vlc *.avi' 

# play all music files from the current directory #
alias playwave = 'for i in *.wav; do mplayer "$i"; done'
alias playogg = 'for i in *.ogg; do mplayer "$i"; done'
alias playmp3 = 'for i in *.mp3; do mplayer "$i"; done'

# play files from nas devices #
alias nplaywave = 'for i in /nas/multimedia/wave/*.wav; do mplayer "$i"; done'
alias nplayogg = 'for i in /nas/multimedia/ogg/*.ogg; do mplayer "$i"; done' 
alias nplaymp3 = 'for i in /nas/multimedia/mp3/*.mp3; do mplayer "$i"; done'

# shuffle mp3/ogg etc by default # 
alias music = 'mplayer --shuffle *'

24:设置系统管理相关命令的默认网卡

vnstat 一款基于终端的网络流量检测器。dnstop 是一款分析 DNS 流量的终端工具。tcptrack 和 iftop 命令显示 TCP/UDP 连接方面的信息,它监控网卡并显示其消耗的带宽。

## All of our servers eth1 is connected to the Internets via vlan / router etc ##
alias dnstop = 'dnstop -l 5 eth1'
alias vnstat = 'vnstat -i eth1'
alias iftop = 'iftop -i eth1' 
alias tcpdump = 'tcpdump -i eth1' 
alias ethtool = 'ethtool eth1' 

# work on wlan0 by default #
# Only useful for laptop as all servers are without wireless interface
alias iwconfig = 'iwconfig wlan0'

25:快速获取系统内存,cpu 使用,和 gpu 内存相关信息

## pass options to free ##
alias meminfo = 'free -m -l -t' 

## get top process eating memory
alias psmem = 'ps auxf | sort -nr -k 4' 
alias psmem10 = 'ps auxf | sort -nr -k 4 | head -10'

## get top process eating cpu ##
alias pscpu = 'ps auxf | sort -nr -k 3'
alias pscpu10 = 'ps auxf | sort -nr -k 3 | head -10' 

## Get server cpu info ##
alias cpuinfo = 'lscpu'

## older system use /proc/cpuinfo ##
##alias cpuinfo='less /proc/cpuinfo' ##

## get GPU ram on desktop / laptop##
alias gpumeminfo = 'grep -i --color memory /var/log/Xorg.0.log'

26:控制家用路由器

curl 命令可以用来 重启 Linksys 路由器。

# Reboot my home Linksys WAG160N / WAG54 / WAG320 / WAG120N Router / Gateway from *nix.
alias rebootlinksys = "curl -u 'admin:my-super-password' 'http://192.168.1.2/setup.cgi?todo=reboot'"

# Reboot tomato based Asus NT16 wireless bridge
alias reboottomato = "ssh [email protected] /sbin/reboot"

27 wget 默认断点续传

GNU wget 是一款用来从 web 下载文件的自由软件。它支持 HTTP,HTTPS,以及 FTP 协议,而且它也支持断点续传:

## this one saved by butt so many times ##
alias wget = 'wget -c'

28 使用不同浏览器来测试网站

## this one saved by butt so many times ##
alias ff4 = '/opt/firefox4/firefox' 
alias ff13 = '/opt/firefox13/firefox' 
alias chrome = '/opt/google/chrome/chrome' 
alias opera = '/opt/opera/opera'

#default ff
alias ff =ff13

#my default browser
alias browser =chrome

29:关于 ssh 别名的注意事项

不要创建 ssh 别名,代之以 ~/.ssh/config 这个 OpenSSH SSH 客户端配置文件。它的选项更加丰富。下面是一个例子:

Host server10
 Hostname 1.2.3.4
 IdentityFile ~/backups/.ssh/id_dsa
 user foobar
 Port 30000
 ForwardX11Trusted yes
 TCPKeepAlive yes

然后你就可以使用下面语句连接 server10 了:

$ ssh server10

30:现在该分享你的别名了

## set some other defaults ##
alias df = 'df -H'
alias du = 'du -ch'

# top is atop, just like vi is vim
alias top = 'atop'

## nfsrestart - must be root ##
## refresh nfs mount / cache etc for Apache ##
alias nfsrestart = 'sync && sleep 2 && /etc/init.d/httpd stop && umount netapp2:/exports/http && sleep 2 && mount -o rw,sync,rsize=32768,wsize=32768,intr,hard,proto=tcp,fsc natapp2:/exports /http/var/www/html && /etc/init.d/httpd start'

## Memcached server status ##
alias mcdstats = '/usr/bin/memcached-tool 10.10.27.11:11211 stats'
alias mcdshow = '/usr/bin/memcached-tool 10.10.27.11:11211 display'

## quickly flush out memcached server ##
alias flushmcd = 'echo "flush_all" | nc 10.10.27.11 11211'

## Remove assets quickly from Akamai / Amazon cdn ##
alias cdndel = '/home/scripts/admin/cdn/purge_cdn_cache --profile akamai'
alias amzcdndel = '/home/scripts/admin/cdn/purge_cdn_cache --profile amazon'

## supply list of urls via file or stdin
alias cdnmdel = '/home/scripts/admin/cdn/purge_cdn_cache --profile akamai --stdin' 
alias amzcdnmdel = '/home/scripts/admin/cdn/purge_cdn_cache --profile amazon --stdin'

总结

本文总结了 *nix bash 别名的多种用法:

  1. 为命令设置默认的参数(例如通过 alias ethtool=’ethtool eth0′ 设置 ethtool 命令的默认参数为 eth0)。

  2. 修正错误的拼写(通过 alias cd..=’cd ..’让 cd.. 变成 cd ..)。

  3. 缩减输入。

  4. 设置系统中多版本命令的默认路径(例如 GNU/grep 位于 /usr/local/bin/grep 中而 Unix grep 位于 /bin/grep 中。若想默认使用 GNU grep 则设置别名 grep=’/usr/local/bin/grep’ )。

  5. 通过默认开启命令(例如 rm,mv 等其他命令)的交互参数来增加 Unix 的安全性。

  6. 为老旧的操作系统(比如 MS-DOS 或者其他类似 Unix 的操作系统)创建命令以增加兼容性(比如 alias del=rm)。

我已经分享了多年来为了减少重复输入命令而使用的别名。若你知道或使用的哪些 bash/ksh/csh 别名能够减少输入,请在留言框中分享。

Linux下通过受限bash创建指定权限的账号

在日常业务运维中,有时为了配合解决问题,需要给非运维人员开通系统账号,用于查询日志或代码。通常为了系统安全或避免不必要的误操作等目的,会将账号权限降至最低。下面介绍下在Linux下通过受限bash创建指定权限账号的操作记录:

[root@mq-server ~]# ln -s /bin/bash  /bin/rbash
[root@mq-server ~]# useradd -s /bin/rbash wangshibo
[root@mq-server ~]# passwd wangshibo
[root@mq-server ~]# mkdir /home/wangshibo/bin
[root@mq-server ~]# chown root. /home/wangshibo/.bash_profile
[root@mq-server ~]# chmod 755 /home/wangshibo/.bash_profile
[root@mq-server ~]# vim /home/wangshibo/.bash_profile       //复制下面的内容覆盖原内容
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$HOME/bin

export PATH<br data-filtered="filtered">
[root@mq-server ~]# ln -s /bin/cat /home/wangshibo/bin/cat
[root@mq-server ~]# ll /home/wangshibo/
total 4
drwxr-xr-x 2 root root 4096 Nov 25 23:38 bin
[root@mq-server ~]# ll /home/wangshibo/bin/
total 0
lrwxrwxrwx 1 root root 8 Nov 25 23:12 cat -> /bin/cat

如上设置后,可以发现创建的wangshibo用户家目录下的文件权限是root.root,上面只设置了wangshibo用户的cat权限,并且只能cat查看wangshibo用户家目录/home/wangshibo下的文件。除了cat命令外。不能执行其他命令!

[wangshibo@mq-server ~]$ cat /var/log/messages
cat: /var/log/messages: Permission denied
[wangshibo@mq-server ~]$ ls
-rbash: /home/wangshibo/bin/ls: No such file or directory
[wangshibo@mq-server ~]$ touch test
-rbash: /home/wangshibo/bin/touch: No such file or directory

如果要想在其家目录下有其他命令的执行权,那么需要添加这些命令的软链接到/home/wangshibo/bin目录下(可以通过which命令查看二进制命令的全路径)

[root@mq-server ~]# ln -s /bin/ls /home/wangshibo/bin
[root@mq-server ~]# ln -s /bin/touch /home/wangshibo/bin
[root@mq-server ~]# ln -s /bin/mkdir /home/wangshibo/bin
[root@mq-server ~]# ln -s /usr/bin/vim /home/wangshibo/bin/
[root@mq-server ~]# ll /home/wangshibo/bin/
total 0
lrwxrwxrwx 1 root root  8 Nov 25 23:12 cat -> /bin/cat
lrwxrwxrwx 1 root root  7 Nov 25 23:44 ls -> /bin/ls
lrwxrwxrwx 1 root root 10 Nov 25 23:45 mkdir -> /bin/mkdir
lrwxrwxrwx 1 root root 10 Nov 25 23:44 touch -> /bin/touch
lrwxrwxrwx 1 root root 12 Nov 25 23:45 vim -> /usr/bin/vim

这样,wangshibo用户就拥有了上面加入的命令的执行权

[root@mq-server ~]# su - wangshibo
[wangshibo@mq-server ~]$ ls
bin
[wangshibo@mq-server ~]$ touch test
[wangshibo@mq-server ~]$ mkdir ops
[wangshibo@mq-server ~]$ vim test
[wangshibo@mq-server ~]$ cat test
dsfdsafsadf
[wangshibo@mq-server ~]$ rm -f test
-rbash: rm: command not found
[wangshibo@mq-server ~]$ ls /usr/
bin  etc  games  include  lib  lib64  libexec  local  sbin  share  src  tmp
[wangshibo@mq-server ~]$ cat /var/log/messages
cat: /var/log/messages: Permission denied