个人工具

UbuntuHelp:Beginners/BashScripting/zh

来自Ubuntu中文

跳转至: 导航, 搜索


Bash 脚本是最容易学习的脚本类型之一,它十分类似于Windows下的批处理脚本. Bash非常的灵活, 而且它有很多你在批处理中无法看到的高级特性. 但如果你对电脑一无所知,那么它对你来说毫无用处. 一般来说,你会喜欢学习Bash,因为大多数在Ubuntu下的日常工作,都可以用终端来解决. 你也会渐渐明白大部分事情都可以通过用户图形界面和命令行来完成, 然而有些事情选择其中一种方法要更容易一些. 例如,使用命令行来更改一个文件夹及其子文件夹中的文件的权限要比使用用户图形界面容易的多.

介绍

在本文中我们将讨论一些有用的日常命令, 而且将深入讨论Bash脚本的高级特性. Bash不仅仅可以用来运行程序,而且还可以用来写程序和脚本.

Bash -- Ubuntu 日常应用

作为一名Ubuntu'er,你会经常的使用终端来处理一些任务,例如

  • 创建文件夹
  • 删除文件
  • 删除文件夹及其子文件夹
  • 以root权限运行程序
  • 备份文件
  • 备份文件夹
  • 检查系统性能
  • 检查设备
  • 检查无线连接

以及许多其他事情, 上表所列就是我们将要讨论的命令.

命令

创建文件夹

创建文件夹可以简单的通过单击鼠标右键然后选择'新建文件夹'来完成, 但是如果你想在命令行环境下完成,你需要在终端中键入以下命令:

sudo mkdir /home/joe/Desktop/new_folder

命令 mkdir (创建目录) 可以创建文件夹,而文件路径会告诉电脑应该在何处创建. (我使用了 sudo ,因为如果你试图在任意位置而不是在'/home'目录或其子目录创建文件夹的话,你需要有root/superuser 用户权限. 下同.)

删除文件

删除文件可以使用如下命令来完成

sudo rm /home/joe/file_to_be_deleted

命令 rm (移除)用来在命令行环境下进行移除操作

删除文件夹及其子文件夹

此命令有可能 (如果错误的使用) 摧毁你的系统!

sudo rm -rf /home/joe/useless_Parent_folder

此命令与前一个命令不同, 它使用了两个选项: '-r'表示递归(将递归的删除文件夹及其子文件夹), '-f' 表示强制(不会再次询问你). 此命令可以完美的删除目录及其子目录. 请注意,以下命令绝对不能执行!!!!绝对不能!!. 除非你想跟你的系统说再见!

sudo rm -rf /*
sudo rm -rf /

这将删除root文件夹内的所有文件,如果你选择的标准安装,这意味着"整个系统.

以root权限运信程序

有时候你需要编辑root文件夹中的配置文件,这时你就需要root权限来保存更改,因此你需要使用root权限来运行文本编辑器. (假设你的文本编辑器是gedit)

gksudo gedit /path/to/conf_file.txt

gksudosudo相同,唯一不同是它会弹出一个对话框来询问你密码, gksudo 用来以root权限运行使用图形界面的程序. 编辑这些系统文件可能导致严重的系统错误. 建议你在编辑它们之前先创建备份文件.

备份文件

要创建备份文件, 我们将要使用 cp (复制) 命令. cp 基本的用法如下所示:

cp source_file dest_file

此命令会复制 'source_file' 到 'dest_file'. 现在可以使用先前的例子,假如我们想要备份 '/path/to/conf_file.txt'. 则输入以下命令:

sudo cp /path/to/conf_file.txt /path/to/conf_file.txt.old

That's fine and dandy, but what if I want to copy my file to another directory? Well that's just as easy. Let's say instead of copying /path/to/conf_file.txt to the /path/to/ directory, you want to copy it to a directory where you store all of your backup files, say /my/backup/folder/. In order to accomplish this you would type:

sudo cp /path/to/conf_file.txt /my/backup/folder/    #saves conf_file.txt to /my/backup/folder/
#OR
sudo cp /path/to/conf_file.txt /my/backup/folder/conf_file_new_name.txt
      • This is a typical safety measure that has saved many users in the past from a complete disaster.***

Okay, so we know how to copy a file a) to a different filename and b) to a different folder. But how do we copy entire directories?

Backing up your directories

To backup one directory to another, we introduce cps '-r' (recursive) option. The basic syntax is as follow:

cp -r /directory/to/be/copied/ /where/to/copy/to/

So if we wanted to copy all of the contents of our /path/to/ folder to our /my/backup/folder, we would type the following:

sudo cp -r /path/to/ /my/backup/folder/foldername    #foldername can be whatever you want the foldername to be

Checking system performance

If your computer starts to lag, you can see which applications are using the most CPU power with this command:

top

This is generally the same information given as the GUI application 'System Monitor'.

Check Devices

USB Devices If a USB device stops working, you may want to see if it is still connected/detected. To check if a device is connected/detected, type the following:

lsusb

PCI Devices PCI devices are checked with:

lspci

Checking wireless connection

To check the status on your wireless connection, use:

iwconfig

This also shows packets sent/received.

Scripting

Bash is primarily a scripting language, so it would be a crime not to talk about scripting. Let's dive straight in with a bash script. More precisely the infamous "Hello World" script. You can create a bash script by opening your favorite text-editor to edit your script and then saving it (typically the .sh file extension is used for your reference, but is not necessary. In our examples, we will be using the .sh extension).

 #!/bin/bash         

echo "Hello, World"

The first line of the script just defines which interpreter to use. NOTE: There is no leading whitespace before #!/bin/bash. That's it, simple as that. To run a bash script you first have to have the correct file permissions. We do this with chmod (change mode) as follows:

sudo chmod 700 /where/i/saved/it/hello_world.sh   #Gives read,write,execute permissions to the Owner
# OR
sudo chmod a+x /where/i/saved/it/hello_world.sh   #Gives everyone execute permissions

This will give the file the appropriate permissions so that it can be executed. Now open a terminal and run the script like this:

/where/i/saved/it/hello_world.sh

Hopefully you should have seen it print Hello, World onto your screen. If so well done! That is your first Bash script. TIP If you type:

pwd

You will see the directory that you are currently working in (pwd stands for 'print working directory'). If your current working directory is /where/i/saved/it/, then you can shorten the above command to:

prompt$ pwd
/where/i/saved/it
prompt$ ./hello_world.sh

Now, lets get to more interesting aspects of Bash programming, Variables!

Variables

Variables store information basically. You set variables like this

var="FOO"

'var' can be anything you want as long as it doesn't begin with a number. "FOO" can be anything you want. To access the information from the variable you need to put a '$' in front of it like this:

var="FOO"
echo $var

Try entering those lines into a terminal one at a time; you will see that the first one just gives you another prompt and the second one prints FOO. But that's all a bit boring. So let's make a script to ask the user for some information and then echo that information.

 #!/bin/bash
clear
echo "Please enter your name"
read name
echo "Please enter your age"
read age
echo "Please enter your sex. Male/Female"
read sex
echo "So you're a $age year old $sex called $name"

read allows the user to input information where it is then stored in the variable defined after the read. read variable would take whatever input the user entered and store it in $variable. We then access this with echo and set up a neat sentence. This script is reasonably messy though; read has another function that could halve the size of this script.

#! /bin/bash
clear
read -p "Please enter your name  : " name
read -p "Please enter your age  : " age
read -p "Please enter your sex. Male/Female  : " sex
echo "So you're a $age year old $sex called $name"

That is more efficient code. However it's still a bit messy when run. A solution? Good old white spaces!

#! /bin/bash
clear
read -p "Please enter your name  : " name
echo ""
read -p "Please enter your age  : " age
echo ""
read -p "Please enter your sex. Male/Female  : " sex
echo ""
echo "So you're a $age year old $sex called $name"

Now we have an efficient and clean Bash script.

If Statements

An if statement can be used to check for something and do something else depending on the outcome of the check. For example, if I had an 'apple', I would want to make sure it's still an 'apple' and not an 'orange' because I don't like Oranges! The syntax for an if statement is

if [something]
	then
	elif
	then
	elif
	then
	....etc....
	else
fi

The elif is not necessary, but it can be used if needed. An if statement to check if our $fruit variable is an 'apple' would look like this

if [ $fruit = apple ]
	then echo "Good, I like Apples"
	else echo "Oh no, I hate Oranges!"
fi

Just to explain this statement,

if [ the contents of $fruit is 'apple' ]
	then say "Good, I like Apples"
	if it's not, then say "Oh no, I hate Oranges!"
finish

If statements are an easy concept to grasp as they are similar to the "if" used in spoken English. But say you wanted to have 4 or 5 checks, the answer may be to write 4 or 5 statements but that's not the most practical way. This is where elif comes in handy.

if [ $fruit = apple ]
	then echo "Good, I like Apples"
elif [ $fruit = pear ]
	then echo "Good, I like Pears"
elif [ $fruit = banana ]
	then echo "Good, I like Bananas"
	else echo "Oh no, I hate Oranges!"
fi

This saves us from from repetitive scripting. There are better ways to check what the fruit is, but we won't go into that now.

Variables

Variables store information basically. You set variables like this

var="FOO"

'var' can be anything you want as long as it doesn't begin with a number. "FOO" can be anything you want. To access the information from the variable you need to put a '$' in front of it like this:

var="FOO"
echo $var

Try entering those lines into a terminal one at a time; you will see that the first one just gives you another prompt and the second one prints FOO. But that's all a bit boring. So let's make a script to ask the user for some information and then echo that information.

 #!/bin/bash
clear
echo "Please enter your name"
read name
echo "Please enter your age"
read age
echo "Please enter your sex. Male/Female"
read sex
echo "So you're a $age year old $sex called $name"

read allows the user to input information where it is then stored in the variable defined after the read. read variable would take whatever input the user entered and store it in $variable. We then access this with echo and set up a neat sentence. This script is reasonably messy though; read has another function that could halve the size of this script.

#! /bin/bash
clear
read -p "Please enter your name  : " name
read -p "Please enter your age  : " age
read -p "Please enter your sex. Male/Female  : " sex
echo "So you're a $age year old $sex called $name"

That is more efficient code. However it's still a bit messy when run. A solution? Good old white spaces!

#! /bin/bash
clear
read -p "Please enter your name  : " name
echo ""
read -p "Please enter your age  : " age
echo ""
read -p "Please enter your sex. Male/Female  : " sex
echo ""
echo "So you're a $age year old $sex called $name"

Now we have an efficient and clean Bash script.

If Statements

An if statement can be used to check for something and do something else depending on the outcome of the check. For example, if I had an 'apple', I would want to make sure it's still an 'apple' and not an 'orange' because I don't like Oranges! The syntax for an if statement is

if [something]
	then
	elif
	then
	elif
	then
	....etc....
	else
fi

The elif is not necessary, but it can be used if needed. An if statement to check if our $fruit variable is an 'apple' would look like this

if [ $fruit = apple ]
	then echo "Good, I like Apples"
	else echo "Oh no, I hate Oranges!"
fi

Just to explain this statement,

if [ the contents of $fruit is 'apple' ]
	then say "Good, I like Apples"
	if it's not, then say "Oh no, I hate Oranges!"
finish

If statements are an easy concept to grasp as they are similar to the "if" used in spoken English. But say you wanted to have 4 or 5 checks, the answer may be to write 4 or 5 statements but that's not the most practical way. This is where elif comes in handy.

if [ $fruit = apple ]
	then echo "Good, I like Apples"
elif [ $fruit = pear ]
	then echo "Good, I like Pears"
elif [ $fruit = banana ]
	then echo "Good, I like Bananas"
	else echo "Oh no, I hate Oranges!"
fi

This saves us from from repetitive scripting. There are better ways to check what the fruit is, but we won't go into that now.

Storing application stdout to a variable:

Application stdout ( what you see on the terminal screen, with an un-piped application ) can be saved and used in Bash. The simplest and most elegant way is to use the back-tick (`) this is not an apostrophe or quote (' or ") and is found on the same key as the tilde (~)

Example

#!/bin/bash
fooVar=`who`
echo $fooVar

This code should output the current users, their respective ttys, and date of login. Note that this strips newlines. Be sure to do any parsing in line ( | grep, etc ) and then pass it to a variable. We will try this again, but grep for tty7, the GUI's tty.

Example 2

fooVar=`who | grep tty7`
echo $fooVar

This should output the single user that is currently logged into the WM. Let's move on to more advanced data manipulation within back ticks.

Example

#!/bin/bash
fooVar=`who`
echo $fooVar

This code should output the current users, their respective ttys, and date of login. Note that this strips newlines. Be sure to do any parsing in line ( | grep, etc ) and then pass it to a variable. We will try this again, but grep for tty7, the GUI's tty.

Example 2

fooVar=`who | grep tty7`
echo $fooVar

This should output the single user that is currently logged into the WM. Let's move on to more advanced data manipulation within back ticks.

FUNctions

Bash lets you create a function on the fly, really handy if you plan on using a code block more then once. Functions reduce the amounts of editing you have to do in a script, if and when you have to update your script. Let's get to it!

Example

Here is an example script:

#!/bin/bash

echo "echo is Called"
echo "Functions are FUN!"
echo "echo is Called"

Although this example is simple, you can see that if you want to change "echo is Called" to say "foo is Called" you would have to edit twice. Below is the same app using functions.

#!/bin/bash
echoFunction() {
  echo "echo is Called"
}
fooBar() {
  echo "Functions are FUN!"
}

echoFunction;
fooBar;
echoFunction;
# You call functions without (), just the function name then a semicolon.

This example, as you can see may be longer now, but you can imagine how, adding features, this will eliminate code and reduce complexity. Also, you can see if you want to change the echo call, you have to edit one line, not two.

Debugging

I always find it useful to trace a script to find out why something does not work as expected. To trace, start it trough bash explicitly and use the -x option, like so:

bash -x ./script.sh

This will write each command to standard error (preceded by a ‘+ ’) before it is executed.

Example

Here is an example script:

#!/bin/bash

echo "echo is Called"
echo "Functions are FUN!"
echo "echo is Called"

Although this example is simple, you can see that if you want to change "echo is Called" to say "foo is Called" you would have to edit twice. Below is the same app using functions.

#!/bin/bash
echoFunction() {
  echo "echo is Called"
}
fooBar() {
  echo "Functions are FUN!"
}

echoFunction;
fooBar;
echoFunction;
# You call functions without (), just the function name then a semicolon.

This example, as you can see may be longer now, but you can imagine how, adding features, this will eliminate code and reduce complexity. Also, you can see if you want to change the echo call, you have to edit one line, not two.

Debugging

I always find it useful to trace a script to find out why something does not work as expected. To trace, start it trough bash explicitly and use the -x option, like so:

bash -x ./script.sh

This will write each command to standard error (preceded by a ‘+ ’) before it is executed.

Debugging

I always find it useful to trace a script to find out why something does not work as expected. To trace, start it trough bash explicitly and use the -x option, like so:

bash -x ./script.sh

This will write each command to standard error (preceded by a ‘+ ’) before it is executed.

Other Scripting Languages related to Bash

tr

tr is one of the most basic applications to pipe data through that uses a basic scripting syntax. In this case, it accepts Regular Expressions. Let's do a normally complicated task, transforming a string to all uppercase.

Example

#!/bin/bash
read foo
var=`echo $foo | tr "{a-z}" "{A-Z}"`
 # {a-z} Matches a through z
 # {A-Z} matches A through Z
echo $var

The output should look something like this:

this is a test
THIS IS A TEST

tr also can TRanslate strings, so let's translate all "tar" in $foo to "bar".

Example

#!/bin/bash
read foo
var=`echo $foo | tr "t" "b"`

the output should look something like this:

I love tars
I love bars

awk

AWK ( Short for Aho, Weinberger & Kernighan ) awk has its own custom scripting language, suitable for a tutorial by itself, so I will cover only the basics to help assist when you are bash scripting. This is not meant to be complete or comprehensive in any way.

pidof clone

Let's make a quick pidof clone that prompts for a process identifier, then echoes the process ID.

#!/bin/bash
read pname
ps -ef | grep -v grep | grep $pname | awk '{print $2}'

Single quotes are used to pass the awk command(s). The curly braces are to use the awk language (for stuff like prints, ifs, etc.). Print prints the column passed given by the $ markup, space delimited. There are a lot more commands than the print command, including if statements, etc., and is worth looking into if you are interested in what you see here!

sed

sed is one of the most complicated scripting languages on the GNU / Linux system. I am only going to cover the s/ command here.

Basic Substitution

Try this out to show that sed can not only replace inline, but unlike tr, replace with a longer or shorter string than before.

#!/bin/bash
read foo
echo $foo | sed "s/foo/bars/"

When this command is run, it should substitute the first appearance of "foo" with "bars". This is an example of the output.

I love to go to foo
I love to go to bars