Bash使用示例(5) – 条件表达式

文件类型测试

-e条件运算符用来测试一个文件是否存在(包括所有文件类型,目录等)

  1. if [[ -e $filename ]]; then
  2.   echo "$filename exists"
  3. fi

也可以测试指定类型的文件

  1. if [[ -f $filename ]]; then
  2.   echo "$filename is a regular file"
  3. elif [[ -d $filename ]]; then
  4.   echo "$filename is a directory"
  5. elif [[ -p $filename ]]; then
  6.   echo "$filename is a named pipe"
  7. elif [[ -S $filename ]]; then
  8.   echo "$filename is a named socket"
  9. elif [[ -b $filename ]]; then
  10.   echo "$filename is a block device"
  11. elif [[ -c $filename ]]; then
  12.   echo "$filename is a character device"
  13. fi
  14. if [[ -L $filename ]]; then
  15.   echo "$filename is a symbolic link (to any file type)"
  16. fi

对于软链接,使用-L测试时,当链接指向的目标文件不存在时会返回false

  1. if [[ -L $filename || -e $filename ]]; then
  2.   echo "$filename exists (but may be a broken symbolic link)"
  3. fi
  4.  
  5. if [[ -L $filename && ! -e $filename ]]; then
  6.   echo "$filename is a broken symbolic link"
  7. fi

字符串比较和匹配

在两个带引号的字符串之间比较时使用==操作符。!=操作符则是否则的比较

  1. if [[ "$string1" == "$string2" ]]; then
  2.   echo "$string1 and $string2 are identical"
  3. fi
  4. if [[ "$string1" == "$string2" ]]; then
  5.   echo "$string1 and $string2 are identical"
  6. fi

如果右则没有引号,那么它是以通配符的模式作比较。

  1. string1=’abc’
  2. pattern=’a*’
  3. if [[ "$string1" == $pattern ]]; then
  4.   # the test is true
  5.   echo "The string $string1 matches the pattern $pattern"
  6. fi
  7. if [[ "$string1" != "$pattern" ]]; then
  8.   echo "The string $string1 is not equal to the string $pattern"
  9. fi

操作符以字典顺序来比较字符串(它们没有小或等于或大于的说法)
可以测试空字符串

  1. if [[ -n $string ]]; then
  2.   echo "$string is non-empty"
  3. fi
  4. if [[ -z "${string// }" ]]; then
  5.   echo "$string is empty or contains only spaces"
  6. fi
  7. if [[ -z $string ]]; then
  8.   echo "$string is empty"
  9. fi

以上的-z检查可能表示$string没有被设置或者已经设置了但为空字符。为了区分空字符和未设置,使用:

  1. if [[ -n ${string+x} ]]; then
  2.     echo "$string is set, possibly to the empty string"
  3. fi
  4. if [[ -n ${string-x} ]]; then
  5.     echo "$string is either unset or set to a non-empty string"
  6. fi
  7. if [[ -z ${string+x} ]]; then
  8.     echo "$string is unset"
  9. fi
  10. if [[ -z ${string-x} ]]; then
  11.     echo "$string is set to an empty string"
  12. fi

其中x是任意的,以表格形式如下:

  1. +——-+——-+———–+
  2.             $string is: | unset | empty | non-empty |
  3. +———————–+——-+——-+———–+
  4. | [[ -z ${string} ]]    | true  | true  | false     |
  5. | [[ -z ${string+x} ]]  | true  | false | false     |
  6. | [[ -z ${string-x} ]]  | false | true  | false     |
  7. | [[ -n ${string} ]]    | false | false | true      |
  8. | [[ -n ${string+x} ]]  | false | true  | true      |
  9. | [[ -n ${string-x} ]]  | true  | false | true      |
  10. +———————–+——-+——-+———–+

文件权限测试

  1. if [[ -r $filename ]]; then
  2.   echo "$filename is a readable file"
  3. fi
  4. if [[ -w $filename ]]; then
  5.   echo "$filename is a writable file"
  6. fi
  7. if [[ -x $filename ]]; then
  8.   echo "$filename is an executable file"
  9. fi

Bash使用示例(4) – 重定向输出

重定向标准输出

> 重定向当前命令的标准输出(STDOUT)到一个文件或者一个描述符。
下面的例子把ls命令的输出存到file.txt文件

  1. ls >file.txt
  2. > file.txt ls

目标文件如果不存在就会被创建,或者文件被截断。
如果不指定,默认重定向描述符是标准输出或1。下面的命令等同于上面的例子:

  1. ls 1>file.txt

追加 vs 截断

截断 >
1.如果文件不存在则创建
2.截断(删除文件内容)
3.写入文件

  1. $ echo "first line" > /tmp/lines
  2. $ echo "second line" > /tmp/lines
  3.  
  4. $ cat /tmp/lines
  5. second line

追加 >>
1.如果文件不存在则创建
2.追加文件(在文件底部写)

  1. # Overwrite existing file
  2. $ echo "first line" > /tmp/lines
  3.  
  4. # Append a second line
  5. $ echo "second line" >> /tmp/lines
  6.  
  7. $ cat /tmp/lines
  8. first line
  9. second line

重定向标准输出和标准错误

文件描述符像0和1都是指针。我们更改的是文件描述符的指向。
>/dev/null意思是1指向/dev/null。
首先我们把1(STDOUT)指向/dev/null,然后2指向1(不管1指向什么)。

  1. echo_to_stdout_and_stderr >/dev/null 2>&1

可以更短点:
echo_to_stdout_and_stderr &> /dev/null

使用命名管道

有时候你想把一个程序的标准输出作为其它多个程序的标准输入,这时候就不能用标准管道了,不过你可以写入一个临时文件,如:

  1. touch tempFile.txt
  2. ls -l > tempFile.txt &
  3. grep ".log" < tempFile.txt

这个方法可以在大多数情况下有效,但谁都不知道tempFile.txt会被哪个程序删除或者修改里面的内容。这时候命名管道就可以用上场了。

  1. mkfifo myPipe
  2. ls -l > myPipe
  3. grep ".log" < myPipe

myPipe在技术上是一个文件,所以我们来用ls -l看下当前创建管道的目录

  1. mkdir pipeFolder
  2. cd pipeFolder
  3. mkfifo myPipe
  4. ls -l

输出为:
prw-r–r– 1 root root 0 Jul 25 11:20 myPipe
注意权限的第一个字符,显示是pipe,不是文件。
现在我们做了有意思的。
打开一个终端,在一个空目录创建管道:

  1. mkfifo myPipe

现在我们输入点东西到管道:

  1. echo "Hello from the other side" > myPipe

你会注意到这个命令被挂起了,让我们打开一个新的终端,输入:

  1. cat < myPipe

你会发现当”hello from the other side”输出后,终端1就完成了,终端2也一样。
现在我们反向运行程序,先执行cat < myPipe,然后再输入点东西到myPipe,它仍然按预期工作,因为一个程序会一起等待直到管道中被输入一些东西。
命名管道在终端间或程序间传递信息时会非常有用。

输出错误信息到标准错误

错误信息通常为了调度会包含在脚本里。简单的输出错误信息如下:

  1. cmd || echo ‘cmd failed’

可能会在简单的场景工作,但不是通常的做法。在这个例子中,错误信息会会污染脚本实际的输出。简单来说,错误信息应该输出到标准错误而不是标准输出,如:

  1. cmd || echo ‘cmd failed’ >/dev/stderr

其它例子:

  1. if cmd; then
  2.     echo ‘success’
  3. else
  4.     echo ‘cmd failed’ >/dev/stderr
  5. fi

可以封装成一个函数:

  1. err(){
  2.     echo "E: $*" >>/dev/stderr
  3. }
  4. err "My error message"

Bash使用示例(3) – 使用trap处理信号

清理临时文件

你可以使用trap命令来捕获信号;shell中的trap捕获信号等同于C语言或大多数其它语言中的signal或者sigaction。
trap最常用的场景之一是在预期退出和意外退出时清理临时文件。
遗憾的是没有多少shell脚本这样做。

  1. #!/bin/sh
  2.  
  3. # Make a cleanup function
  4. cleanup() {
  5.   rm –force — "${tmp}"
  6. }
  7.  
  8. # Trap the special "EXIT" group, which is always run when the shell exits.
  9. trap cleanup EXIT
  10.  
  11. # Create a temporary file
  12. tmp="$(mktemp -p /tmp tmpfileXXXXXXX)"
  13.  
  14. echo "Hello, world!" >> "${tmp}"
  15.  
  16. # No rm -f "$tmp" needed. The advantage of using EXIT is that it still works
  17. # even if there was an error or if you used exit.

捕获SIGINT或Ctrl+C信号

当有子shell时,trap会被重置,所以sleep继续作用于由^C发送的SIGINT信号,而父进程(即shell脚本)就不会了。所以下面的例子只是退出了sleep,没有直接退出shell脚本,而是继续往下执行。

  1. #!/bin/sh
  2.  
  3. # Run a command on signal 2 (SIGINT, which is what ^C sends)
  4. sigint() {
  5.     echo "Killed subshell!"
  6. }
  7. trap sigint INT
  8.  
  9. # Or use the no-op command for no output
  10. #trap : INT
  11.  
  12. # This will be killed on the first ^C
  13. echo "Sleeping…"
  14. sleep 500
  15.  
  16. echo "Sleeping…"
  17. sleep 500

通过些许更改可以允许你按两个^C才退出程序:

  1. last=0
  2. allow_quit() {
  3.     [ $(date +%s) -lt $(( $last + 1 )) ] && exit
  4.     echo "Press ^C twice in a row to quit"
  5.     last=$(date +%s)
  6. }
  7. trap allow_quit INT

统计维护退出任务

你有没有在退出时忘记添加trap来清理临时文件或者其它事情?
有没有设置了一个trap而导致取消了另一个?
下面的代码能让你非常容易地在一个地方就把所有需要在退出时做的工作都添加进去,而不是需要一大段的trap声明,这个很容易忘记的。

  1. # on_exit and add_on_exit
  2. # Usage:
  3. #   add_on_exit rm -f /tmp/foo
  4. #   add_on_exit echo "I am exiting"
  5. #   tempfile=$(mktemp)
  6. #   add_on_exit rm -f "$tempfile"
  7. # Based on http://www.linuxjournal.com/content/use-bash-trap-statement-cleanup-temporary-files
  8. function on_exit()
  9. {
  10.     for i in "${on_exit_items[@]}"
  11.     do
  12.         eval $i
  13.     done
  14. }
  15. function add_on_exit()
  16. {
  17.     local n=${#on_exit_items[*]}
  18.     on_exit_items[$n]="$*"
  19.     if [[ $n -eq 0 ]]; then
  20.         trap on_exit EXIT
  21.     fi
  22. }

退出时杀掉子进程

Trap表达式不一定需要单独的函数或者程序,它也可以直接使用复杂的表达式,如:

  1. trap ‘jobs -p | xargs kill’ EXIT

Bash使用示例(2) – 内部变量

$@

“$@”把所有的命令行参数作为一个数组返回。与”$*”不一样,它是作为一个字符串来返回。
“$@”可以通过循环来遍历所有元素,如下脚本:

  1. #!/bin/bash
  2. for var in "$*"; do
  3.     echo $var
  4. done

因为$*只把参数作为一个字符串返回,echo就只被调用一次:

  1. ~> $ ./testscript.sh firstarg secondarg thirdarg
  2. firstarg secondarg thirdarg

使用$@时:

  1. #!/bin/bash
  2. for var in "$@"; do
  3.     echo $var
  4. done

以数组返回所有参数,使用你能够单独地访问每一个参数:

  1. ~> $ ./testscript.sh firstarg secondarg thirdarg
  2. firstarg
  3. secondarg
  4. thirdarg

$#

获取命令行参数个数,键入:

  1. #!/bin/bash
  2. echo "$#"

如带3个参数运行脚本,输出如下:

  1. ~> $ ./testscript.sh firstarg secondarg thirdarg
  2. 3

$!

返回上一个程序执行的进程ID:

  1. ~> $ ls &
  2. testfile1 testfile2
  3. [1]+  Done                    ls
  4. ~> $ echo $!
  5. 21715

$$

当前进程的pid,如果在bash命令行下执行,相当于是bash进程的pid:

  1. ~> $ echo $$
  2. 13246

$*

以单个字符串返回所有命令行参数。
testscript.sh:

  1. #!/bin/bash
  2. echo "$*"

带几个参数运行脚本:

  1. ./testscript.sh firstarg secondarg thirdarg

输出:

  1. firstarg secondarg thirdarg

$?

返回上一次函数或命令执行的退出状态。通过0表示执行成功,其它的则表示执行失败:

  1. ~> $ ls *.blah;echo $?
  2. ls: cannot access *.blah: No such file or directory
  3. 2
  4. ~> $ ls;echo $?
  5. testfile1 testfile2
  6. 0

$1 $2 $3等

从命令行传递给脚本或者一个函数的位置参数:

  1. #!/bin/bash
  2. # $n is the n’th positional parameter
  3. echo "$1"
  4. echo "$2"
  5. echo "$3"

输出如下:
~> $ ./testscript.sh firstarg secondarg thirdarg

  1. firstarg
  2. secondarg
  3. thirdarg

如果位置参数的数量大于9,需要使用大括号:

  1. #  "set — " sets positional parameters
  2. set — 1 2 3 4 5 6 7 8 nine ten eleven twelfe
  3. echo $10   # outputs 1
  4. echo ${10} # outputs ten

$FUNCNAME

获取当前函数的名称:

  1. my_function()
  2. {
  3.     echo "This function is $FUNCNAME"    # This will output "This function is my_function"
  4. }

如果在函数外打印此变量:

  1. my_function
  2.  
  3. echo "This function is $FUNCNAME"    # This will output "This function is"

$HOME

用户的主目录

  1. ~> $ echo $HOME
  2. /home/user

$IFS

此变量包含用于循环中bash拆分字符串的内部字段分隔符。默认是空白字符n(newline),t(tab)或者空格。更改它的话使你能够使用不同分隔符拆分字符串:

  1. IFS=","
  2. INPUTSTR="a,b,c,d"
  3. for field in ${INPUTSTR}; do
  4.     echo $field
  5. done

输出:
a
b
c
d

$PWD

输出当前工作目录

  1. ~> $ echo $PWD
  2. /home/user
  3. ~> $ cd directory
  4. directory> $ echo $PWD
  5. /home/user/directory

$HOSTNAME

系统启动时分配的主机名

  1. ~> $ echo $HOSTNAME
  2. mybox.mydomain.com

$LINENO

输出脚本的当前行号。在调试脚本时可能会用到。

  1. #!/bin/bash
  2. # this is line 2
  3. echo something  # this is line 3
  4. echo $LINENO # Will output 4

Bash使用示例(1) – 数组

数组赋值

列表赋值

用新元素创建数组

  1. array=(‘first element’ ‘second element’ ‘third element’)

下标赋值

显式指定元素索引创建数组:

  1. array=([3]=’fourth element’ [4]=’fifth element’)

按索引赋值

  1. array[0]=’first element’
  2. array[1]=’second element’

按名称赋值(关联数组)

  1. declare -A array
  2. array[first]=’First element’
  3. array[second]=’Second element’

动态赋值

以其它命令的输出创建一个数组,例如使用seq创建一个从1到10的数组:

  1. array=(`seq 1 10`)

从脚本参数创建数组

  1. array=("$@")

循环内赋值

  1. while read -r; do
  2.     #array+=("$REPLY")     # Array append
  3.     array[$i]="$REPLY"     # Assignment by index
  4.     let i++                # Increment index
  5. done < <(seq 1 10)  # command substitution
  6. echo ${array[@]}    # output: 1 2 3 4 5 6 7 8 9 10

访问数组元素

打印索引为0的元素

  1. echo "${array[0]}"

打印最后一个元素(从Bash 4.3可用)

  1. echo "${array[-1]}"

打印从索引1开始的元素

  1. echo "${array[@]:1}"

打印从索引1开始的3个元素

  1. echo "${array[@]:1:3}"

数组更改

按索引更改

初始化或者更新数组中的一个特定元素

  1. array[10]="elevenths element"    # because it’s starting with 0

追回

修改数组,追加元素到数组结尾

  1. array+=(‘fourth element’ ‘fifth element’)

添加元素到数组开头

  1. array=("new element" "${array[@]}")

插入

给定索引值插入一个元素

  1. arr=(a b c d)
  2. # insert an element at index 2
  3. i=2
  4. arr=("${arr[@]:0:$i}" ‘new’ "${arr[@]:$i}")
  5. echo "${arr[2]}" #output: new

删除

使用uset删除指定索引元素

  1. arr=(a b c)
  2. echo "${arr[@]}"   # outputs: a b c
  3. echo "${!arr[@]}"  # outputs: 0 1 2
  4. unset -v ‘arr[1]’
  5. echo "${arr[@]}"   # outputs: a c
  6. echo "${!arr[@]}"  # outputs: 0 2

重排索引

当有一些元素从数组被删除时,可以使用下面方法重排索引,或者你不知道索引是否存在时隙时会有用。

  1. array=("${array[@]}")

数组长度

${#array[@]}可以得到${array[@]}数组的长度

  1. array=(‘first element’ ‘second element’ ‘third element’)
  2. echo "${#array[@]}" # gives out a length of 3

迭代数组元素

  1. fileList=( file1.txt file2.txt file3.txt )
  2.  
  3. # Within the for loop, $file is the current file
  4. for file in "${fileList[@]}"
  5. do
  6.   echo "$file"
  7. done

Docker使用示例(5) – 查看容器信息

查看容器信息

  1. docker inspect -f ‘<format>’ <container>

查看网络设置

  1. docker inspect -f ‘{{ .NetworkSettings }}’ <container>

以json格式输出:

  1. docker inspect -f ‘{{ json.NetworkSettings }}’ <container>

获取IP地址

  1. docker inspect -f ‘{{ .NetworkSettings.IPAddress }}’ <container>
  2. <container>

当docker inspect输出多个同类的元素时,我们可以获取指定次序的元素,如获取Config.Env第一个元素:

  1. docker inspect –format ‘{{ index (index .Config.Env) 0 }}’ <container>

也可以获取元素的数量:

  1. docker inspect –format ‘{{ len .Config.Env }}’ <container>

Docker使用示例(4) – 清理容器和镜像

清理容器

清理已停止的容器:

  1. docker rm $(docker ps -qa)

清理所有容器,包括正在运行的和停止的:

  1. docker rm -f $(docker ps -qa)

删除僵死容器

  1. docker rm $(docker ps –all -q -f status=dead)

删除已退出的容器

  1. docker rm $(docker ps –all -q -f status=exited)

清理镜像

清理未生成过容器的镜像

  1. docker rmi $(docker images -qa)

清理所有镜像

  1. docker rmi -f $(docker images -qa)

清理没有tag的镜像

  1. docker images -q -f dangling=true | xargs –no-run-if-empty –delim=’n’ docker rmi

Docker使用示例(3) – 调试容器

打印日志

通过跟踪日志调试正在运行的程序是一种较少干扰的方法。下面的例子相当于在容器中执行了tail -f some-application.log命令。

  1. docker logs –follow –tail 10 7786807d8084

如果你的日志里没有包含时间戳,可以添加–timestamps标志。

监控资源占用

监控系统资源使用情况是一种比较有效找到资源占用过多的程序的方法。下面的例子与通常使用的top命令一样。

  1. docker stats

可以监控几个指定容器的资源:

  1. docker stats 7786807d8084 7786807d8085

Docker统计显示如下信息:
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
7786807d8084 0.65% 1.33 GB / 3.95 GB 33.67% 142.2 MB / 57.79 MB 46.32 MB / 0 B
默认情况下,docker stats命令显示的是容器的id,这对于识别容器没什么帮助,如果你想显示容器的名称,可以使用:

  1. docker stats $(docker ps –format ‘{{.Names}}’)

监控容器里的进程

下面的例子相当于传统的ps命令:

  1. docker top 7786807d8084

可以监控指定的进程,如faux:

  1. docker top 7786807d8084 faux

或者获取以root运行的进程列表:

  1. docker top 7786807d8084 -u root

Docker使用示例(2) – 管理容器

列出容器

  1. $ docker ps
  2. CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
  3. 2bc9b1988080        redis               "docker-entrypoint.sh"   2 weeks ago         Up 2 hours          0.0.0.0:6379->6379/tcp    elephant-redis
  4. 817879be2230        postgres            "/docker-entrypoint.s"   2 weeks ago         Up 2 hours          0.0.0.0:65432->5432/tcp   pt-postgres

docker ps只列出正在运行的容器。要查看所有容器(包括已停止的),使用-a选项:

  1. $ docker ps -a
  2. CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS                     NAMES
  3. 9cc69f11a0f7        docker/whalesay     "ls /"                   26 hours ago        Exited (0) 26 hours ago                             berserk_wozniak
  4. 2bc9b1988080        redis               "docker-entrypoint.sh"   2 weeks ago         Up 2 hours                0.0.0.0:6379->6379/tcp    elephant-redis
  5. 817879be2230        postgres            "/docker-entrypoint.s"   2 weeks ago         Up 2 hours                0.0.0.0:65432->5432/tcp   pt-postgres

要列出特定状态的容器,可以使用-f选项指定。如下例子是列出已经退出的容器:

  1. $ docker ps -a -f status=exited
  2. CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS                     NAMES
  3. 9cc69f11a0f7        docker/whalesay     "ls /"                   26 hours ago        Exited (0) 26 hours ago

也可以使用-q选项来列出容器的ID:

  1. $ docker ps -aq
  2. 9cc69f11a0f7
  3. 2bc9b1988080
  4. 817879be2230

如果在生成容器时使用了–name mycontainer1指定名称,我们可以使用此名称来找到这个容器:

  1. docker ps -f name=mycontainer1

引用容器

Docker命令可以使用以下三种方式来引用容器:
Full UUID:9cc69f11a0f76073e87f25cb6eaf0e079fbfbd1bc47c063bcd25ed3722a8cc4a
Short UUID:9cc69f11a0f7
Name:berserk_wozniak
使用docker ps可以看到这三种形式。
UUID是Docker自动生成的,不能更改。你可以使用–name来指定一个你的名称。如果不指定,Docker则会分配一个随机的名称。

删除所有退出的容器

  1. docker ps -aq -f status=exited | xargs -r docker rm

其中docker ps -aq -f status=exited会列出所有已退出的容器的ID
或者使用:

  1. docker rm $(docker ps -aq -f status=exited)

连接后台运行的容器

  1. docker attach –sig-proxy=false <container>

使用这个命令会连接到容器的bash,意味着如果容器里运行着一个脚本,你会看到脚本的输出。
如果要断开连接,使用Ctrl-P Ctrl-Q。
如果要创建一个新的容器bash环境并进入,可以使用:

  1. docker exec -it <container> bash

从/到容器复制文件

从容器到宿主:

  1. docker cp CONTAINER_NAME:PATH_IN_CONTAINER PATH_IN_HOST

从宿主到容器:

  1. docker cp PATH_IN_HOST CONTAINER_NAME:PATH_IN_CONTAINER

启动/停止/重启容器

启动:

  1. docker start <container> [<container>…]

停止:

  1. docker stop <container> [<container>…]

重启:

  1. docker restart <container> [<container>…]

Docker使用示例(1) – 创建容器

容器运行后自动删除

一般情况下,退出一个Docker容器后它仍然会存在。这允许你再次运行容器,查看其文件系统等。不过,有时候你可能想运行容器后马上自动删除。例如想执行一个命令或者查看一个文件。Docker为此提供了一个–rm命令行参数来实现它。

  1. docker run –rm ubuntu cat /etc/hosts

这会从ubuntu镜像创建一个容器,显示/etc/hosts的内容,然后退出后立即销毁容器。
这避免了你只是想做下实验后再清理容器的麻烦。
注意:–rm选项在与-d(–detach)选项时失效。
当使用–rm选项时,Docker被删除后也会删除与之关系的volumes。这与执行docker rm -v my-container类似。只删除未命名的volumes。
例如,运行docker run -it –rm -v /etc -v logs:/var/log centos /bin/produce_some_logs,/etc数据卷会被删除,/var/log则不会。

容器重启策略

  1. docker run –restart=always -d <container>

默认情况下,当Docker守护进程重启时(如主机系统重启),容器不会跟着重启。Docker为容器提供了一个重启策略,选项为–restart=always。使用此选项一旦Docker守护里程重启后,容器也会重启。
不过,如果是手动停止的容器(如docker stop ),重启策略则不会生效。

设置容器名称

默认下,使用docker run创建容器时会分配一个随机的名称,如small_roentgen或modest_dubinsky。这种名称对识别容器不会有任何帮助。我们可以通过–name选项来指定一个有意义的名称。

  1. docker run –name my-ubuntu ubuntu:14.04

名称必须是唯一的。如果指定了一个与正在运行容器的名称一样,docker会报错并且不会创建任何容器。

后台运行容器

为了让容器在后台运行,我们可以在生成容器时使用-d选项。

  1. docker run -d busybox top

给容器分配数据卷

Docker 数据卷(volume)其实是一个文件或者目录,它在容器生命周期结束后还会保留。我们可以挂载宿主机的一个文件或目录作为Docker的数据卷。
使用-v选项添加一个数据卷:

  1. docker run -d -v "/data" awesome/app bootstrap.sh

这会创建一个数据卷并把它挂载到容器的/data目录。

挂载宿主目录

挂载宿主文件或目录到容器:

  1. docker run -d -v "/home/foo/data:/data" awesome/app bootstrap.sh

这会把宿主的/home/foo/data目录挂载到容器里的/data目录。这个操作就会Linux的mount命令。因此这个挂载只存在于容器的生命周期。更改宿主/home/foo/data的文件会立即影响到容器的/data对应的文件里,因为它们是指向硬盘上的同一个文件。

命名数据卷

可以在创建数据卷时指定一个名称,而不只是主机目录路径。

  1. docker run -d -v "my-volume:/data" awesome/app bootstrap.sh

命名的数据卷创建后,可以通过此名称来与其它容器共享。

交互方式运行容器

使用-it选项来以交互方式运行容器。

  1. $ docker run -it ubuntu:14.04 bash
  2. root@8ef2356d919a:/# echo hi
  3. hi
  4. root@8ef2356d919a:/#

-i选项保持STDIN打开,而-t则分配一个伪TTY。

登录正在运行的容器

我们可以使用如下命令来登录正在运行的容器

  1. docker exec -it jovial_morse bash