热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

奇珍异宝

在我们bash学习旅程中的最后一站,我们将看一些零星的知识点。当然我们在之前的章节中已经涵盖了很多方面,但是还有许多bash特性我们没有涉及到。其中大部

在我们 bash 学习旅程中的最后一站,我们将看一些零星的知识点。当然我们在之前的章节中已经 涵盖了很多方面,但是还有许多 bash 特性我们没有涉及到。其中大部分特性相当晦涩,主要对 那些把 bash 集成到 Linux 发行版的程序有用处。然而还有一些特性,虽然不常用, 但是对某些程序问题是很有帮助的。我们将在这里介绍它们。


组命令和子 shell

bash 允许把命令组合在一起。可以通过两种方式完成;要么用一个 group 命令,要么用一个子 shell。 这里是每种方式的语法示例:

组命令:

{ command1; command2; [command3; ...] }

子 shell:

(command1; command2; [command3;...])

这两种形式的不同之处在于,组命令用花括号把它的命令包裹起来,而子 shell 用括号。值得注意的是,鉴于 bash 实现组命令的方式, 花括号与命令之间必须有一个空格,并且最后一个命令必须用一个分号或者一个换行符终止。

那么组命令和子 shell 命令对什么有好处呢? 尽管它们有一个很重要的差异(我们马上会接触到),但它们都是用来管理重定向的。 让我们考虑一个对多个命令执行重定向的脚本片段。

ls -l > output.txt
echo "Listing of foo.txt" >> output.txt
cat foo.txt >> output.txt

这些代码相当简洁明了。三个命令的输出都重定向到一个名为 output.txt 的文件中。 使用一个组命令,我们可以重新编 写这些代码,如下所示:

{ ls -l; echo "Listing of foo.txt"; cat foo.txt; } > output.txt

使用一个子 shell 是相似的:

(ls -l; echo "Listing of foo.txt"; cat foo.txt) > output.txt

使用这样的技术,我们为我们自己节省了一些打字时间,但是组命令和子 shell 真正闪光的地方是与管道线相结合。 当构建一个管道线命令的时候,通常把几个命令的输出结果合并成一个流是很有用的。 组命令和子 shell 使这种操作变得很简单:

{ ls -l; echo "Listing of foo.txt"; cat foo.txt; } | lpr

这里我们已经把我们的三个命令的输出结果合并在一起,并把它们用管道输送给命令 lpr 的输入,以便产生一个打印报告。

在下面的脚本中,我们将使用组命令,看几个与关联数组结合使用的编程技巧。这个脚本,称为 array-2,当给定一个目录名,打印出目录中的文件列表, 伴随着每个文件的文件所有者和组所有者。在文件列表的末尾,脚本打印出属于每个所有者和组的文件数目。 这里我们看到的结果(缩短的,为简单起见),是给定脚本的目录为 /usr/bin 的时候:

[me@linuxbox ~]$ array-2 /usr/bin
/usr/bin/2to3-2.6 root root
/usr/bin/2to3 root root
/usr/bin/a2p root root
/usr/bin/abrowser root root
/usr/bin/aconnect root root
/usr/bin/acpi_fakekey root root
/usr/bin/acpi_listen root root
/usr/bin/add-apt-repository root root
.
/usr/bin/zipgrep root root
/usr/bin/zipinfo root root
/usr/bin/zipnote root root
/usr/bin/zip root root
/usr/bin/zipsplit root root
/usr/bin/zjsdecode root root
/usr/bin/zsoelim root rootFile owners:
daemon : 1 file(s)
root : 1394 file(s) File group owners:
crontab : 1 file(s)
daemon : 1 file(s)
lpadmin : 1 file(s)
mail : 4 file(s)
mlocate : 1 file(s)
root : 1380 file(s)
shadow : 2 file(s)
ssh : 1 file(s)
tty : 2 file(s)
utmp : 2 file(s)

这里是脚本代码列表(带有行号):

#!/bin/bash# array-2: Use arrays to tally file ownersdeclare -A files file_group file_owner groups ownersif [[ ! -d "$1" ]]; thenecho "Usage: array-2 dir" >&2exit 1fifor i in "$1"/*; doowner=$(stat -c %U "$i")group=$(stat -c %G "$i")files["$i"]="$i"file_owner["$i"]=$ownerfile_group["$i"]=$group((++owners[$owner]))((++groups[$group]))done# List the collected files{ for i in "${files[@]}"; doprintf "%-40s %-10s %-10s\n" \"$i" ${file_owner["$i"]} ${file_group["$i"]}done } | sortecho# List ownersecho "File owners:"{ for i in "${!owners[@]}"; doprintf "%-10s: %5d file(s)\n" "$i" ${owners["$i"]}done } | sortecho# List groupsecho "File group owners:"{ for i in "${!groups[@]}"; doprintf "%-10s: %5d file(s)\n" "$i" ${groups["$i"]}done } | sort

让我们看一下这个脚本的运行机制:

行5: 关联数组必须用带有 -A 选项的 declare 命令创建。在这个脚本中我们创建了如下五个数组:

files 包含了目录中文件的名字,按文件名索引

file_group 包含了每个文件的组所有者,按文件名索引

file_owner 包含了每个文件的所有者,按文件名索引

groups 包含了属于索引的组的文件数目

owners 包含了属于索引的所有者的文件数目

行7-10:查看是否一个有效的目录名作为位置参数传递给程序。如果不是,就会显示一条使用信息,并且脚本退出,退出状态为1。

行12-20:循环遍历目录中的所有文件。使用 stat 命令,行13和行14抽取文件所有者和组所有者, 并把值赋给它们各自的数组(行16,17),使用文件名作为数组索引。同样地,文件名自身也赋值给 files 数组。

行18-19:属于文件所有者和组所有者的文件总数各自加1。

行22-27:输出文件列表。为做到这一点,使用了 “${array[@]}” 参数展开,展开成整个的数组元素列表, 并且每个元素被当做是一个单独的词。从而允许文件名包含空格的情况。也要注意到整个循环是包裹在花括号中, 从而形成了一个组命令。这样就允许整个循环输出会被管道输送给 sort 命令的输入。这是必要的,因为 展开的数组元素是无序的。

行29-40:这两个循环与文件列表循环相似,除了它们使用 “${!array[@]}” 展开,展开成数组索引的列表 而不是数组元素的。


进程替换

虽然组命令和子 shell 看起来相似,并且它们都能用来在重定向中合并流,但是两者之间有一个很重要的不同。 然而,一个组命令在当前 shell 中执行它的所有命令,而一个子 shell(顾名思义)在当前 shell 的一个 子副本中执行它的命令。这意味着运行环境被复制给了一个新的 shell 实例。当这个子 shell 退出时,环境副本会消失, 所以在子 shell 环境(包括变量赋值)中的任何更改也会消失。因此,在大多数情况下,除非脚本要求一个子 shell, 组命令比子 shell 更受欢迎。组命令运行很快并且占用的内存也少。

我们在第20章中看到过一个子 shell 运行环境问题的例子,当我们发现管道线中的一个 read 命令 不按我们所期望的那样工作的时候。为了重现问题,我们构建一个像这样的管道线:

echo "foo" | read
echo $REPLY

该 REPLY 变量的内容总是为空,是因为这个 read 命令在一个子 shell 中执行,所以它的 REPLY 副本会被毁掉, 当该子 shell 终止的时候。因为管道线中的命令总是在子 shell 中执行,任何给变量赋值的命令都会遭遇这样的问题。 幸运地是,shell 提供了一种奇异的展开方式,叫做进程替换,它可以用来解决这种麻烦。进程替换有两种表达方式:

一种适用于产生标准输出的进程:

<(list)

另一种适用于接受标准输入的进程&#xff1a;

>(list)

这里的 list 是一串命令列表&#xff1a;

为了解决我们的 read 命令问题&#xff0c;我们可以雇佣进程替换&#xff0c;像这样&#xff1a;

read <<(echo "foo")
echo $REPLY

进程替换允许我们把一个子 shell 的输出结果当作一个用于重定向的普通文件。事实上&#xff0c;因为它是一种展开形式&#xff0c;我们可以检验它的真实值&#xff1a;

[me&#64;linuxbox ~]$ echo <(echo "foo")
/dev/fd/63

通过使用 echo 命令&#xff0c;查看展开结果&#xff0c;我们看到子 shell 的输出结果&#xff0c;由一个名为 /dev/fd/63 的文件提供。

进程替换经常被包含 read 命令的循环用到。这里是一个 read 循环的例子&#xff0c;处理一个目录列表的内容&#xff0c;内容创建于一个子 shell&#xff1a;

#!/bin/bash
# pro-sub : demo of process substitution
while read attr links owner group size date time filename; docat <<- EOFFilename: $filenameSize: $sizeOwner: $ownerGroup: $groupModified: $date $timeLinks: $linksAttributes: $attrEOF
done <<(ls -l | tail -n &#43;2)

这个循环对目录列表的每一个条目执行 read 命令。列表本身产生于该脚本的最后一行代码。这一行代码把从进程替换得到的输出 重定向到这个循环的标准输入。这个包含在管道线中的 tail 命令&#xff0c;是为了消除列表的第一行文本&#xff0c;这行文本是多余的。

当脚本执行后&#xff0c;脚本产生像这样的输出&#xff1a;

[me&#64;linuxbox ~]$ pro_sub | head -n 20
Filename: addresses.ldif
Size: 14540
Owner: me
Group: me
Modified: 2009-04-02 11:12
Links:
1
Attributes: -rw-r--r--
Filename: bin
Size: 4096
Owner: me
Group: me
Modified: 2009-07-10 07:31
Links: 2
Attributes: drwxr-xr-x
Filename: bookmarks.html
Size: 394213
Owner: me
Group: me

陷阱

在第10章中&#xff0c;我们看到过程序是怎样响应信号的。我们也可以把这个功能添加到我们的脚本中。然而到目前为止&#xff0c; 我们所编写过的脚本还不需要这种功能&#xff08;因为它们运行时间非常短暂&#xff0c;并且不创建临时文件&#xff09;&#xff0c;大且更复杂的脚本 可能会受益于一个信息处理程序。

当我们设计一个大的&#xff0c;复杂的脚本的时候&#xff0c;若脚本仍在运行时&#xff0c;用户注销或关闭了电脑&#xff0c;这时候会发生什么&#xff0c;考虑到这一点非常重要。 当像这样的事情发生了&#xff0c;一个信号将会发送给所有受到影响的进程。依次地&#xff0c;代表这些进程的程序会执行相应的动作&#xff0c;来确保程序 合理有序的终止。比方说&#xff0c;例如&#xff0c;我们编写了一个会在执行时创建临时文件的脚本。在一个好的设计流程&#xff0c;我们应该让脚本删除创建的 临时文件&#xff0c;当脚本完成它的任务之后。若脚本接收到一个信号&#xff0c;表明该程序即将提前终止的信号&#xff0c; 此时让脚本删除创建的临时文件&#xff0c;也会是很精巧的设计。

为满足这样需求&#xff0c;bash 提供了一种机制&#xff0c;众所周知的 trap。陷阱由被恰当命令的内部命令 trap 实现。 trap 使用如下语法&#xff1a;

trap argument signal [signal...]

这里的 argument 是一个字符串&#xff0c;它被读取并被当作一个命令&#xff0c;signal 是一个信号的说明&#xff0c;它会触发执行所要解释的命令。

这里是一个简单的例子&#xff1a;

#!/bin/bash
# trap-demo : simple signal handling demo
trap "echo &#39;I am ignoring you.&#39;" SIGINT SIGTERM
for i in {1..5}; doecho "Iteration $i of 5"sleep 5
done

这个脚本定义一个陷阱&#xff0c;当脚本运行的时候&#xff0c;这个陷阱每当接受到一个 SIGINT 或 SIGTERM 信号时&#xff0c;就会执行一个 echo 命令。 当用户试图通过按下 Ctrl-c 组合键终止脚本运行的时候&#xff0c;该程序的执行结果看起来像这样&#xff1a;

[me&#64;linuxbox ~]$ trap-demo
Iteration 1 of 5
Iteration 2 of 5
I am ignoring you.
Iteration 3 of 5
I am ignoring you.
Iteration 4 of 5
Iteration 5 of 5

正如我们所看到的&#xff0c;每次用户试图中断程序时&#xff0c;会打印出这条信息。

构建一个字符串形成一个有用的命令序列是很笨拙的&#xff0c;所以通常的做法是指定一个 shell 函数作为命令。在这个例子中&#xff0c; 为每一个信号指定了一个单独的 shell 函数来处理&#xff1a;

#!/bin/bash
# trap-demo2 : simple signal handling demo
exit_on_signal_SIGINT () {echo "Script interrupted." 2>&1exit 0
}
exit_on_signal_SIGTERM () {echo "Script terminated." 2>&1exit 0
}
trap exit_on_signal_SIGINT SIGINT
trap exit_on_signal_SIGTERM SIGTERM
for i in {1..5}; doecho "Iteration $i of 5"sleep 5
done

这个脚本的特色是有两个 trap 命令&#xff0c;每个命令对应一个信号。每个 trap&#xff0c;依次&#xff0c;当接受到相应的特殊信号时&#xff0c; 会执行指定的 shell 函数。注意每个信号处理函数中都包含了一个 exit 命令。没有 exit 命令&#xff0c; 信号处理函数执行完后&#xff0c;该脚本将会继续执行。

当用户在这个脚本执行期间&#xff0c;按下 Ctrl-c 组合键的时候&#xff0c;输出结果看起来像这样&#xff1a;

[me&#64;linuxbox ~]$ trap-demo2
Iteration 1 of 5
Iteration 2 of 5
Script interrupted.

临时文件

把信号处理程序包含在脚本中的一个原因是删除临时文件&#xff0c;在脚本执行期间&#xff0c;脚本可能会创建临时文件来存放中间结果。 命名临时文件是一种艺术。传统上&#xff0c;在类似于 unix 系统中的程序会在 /tmp 目录下创建它们的临时文件&#xff0c;/tmp 是 一个服务于临时文件的共享目录。然而&#xff0c;因为这个目录是共享的&#xff0c;这会引起一定的安全顾虑&#xff0c;尤其对那些用 超级用户特权运行的程序。除了为暴露给系统中所有用户的文件设置合适的权限&#xff0c;这一明显步骤之外&#xff0c; 给临时文件一个不可预测的文件名是很重要的。这就避免了一种为大众所知的 temp race 攻击。 一种创建一个不可预测的&#xff08;但是仍有意义的&#xff09;临时文件名的方法是&#xff0c;做一些像这样的事情&#xff1a;

tempfile&#61;/tmp/$(basename $0).$.$RANDOM

这将创建一个由程序名字&#xff0c;程序进程的 ID&#xff08;PID&#xff09;文件名&#xff0c;和一个随机整数组成。注意&#xff0c;然而&#xff0c;该 $RANDOM shell 变量 只能返回一个范围在1-32767内的整数值&#xff0c;这在计算机术语中不是一个很大的范围&#xff0c;所以一个单一的该变量实例是不足以克服一个坚定的攻击者的。

一个比较好的方法是使用 mktemp 程序&#xff08;不要和 mktemp 标准库函数相混淆&#xff09;来命名和创建临时文件。 这个 mktemp 程序接受一个用于创建文件名的模板作为参数。这个模板应该包含一系列的 “X” 字符&#xff0c; 随后这些字符会被相应数量的随机字母和数字替换掉。一连串的 “X” 字符越长&#xff0c;则一连串的随机字符也就越长。 这里是一个例子&#xff1a;

tempfile&#61;$(mktemp /tmp/foobar.$.XXXXXXXXXX)

这里创建了一个临时文件&#xff0c;并把临时文件的名字赋值给变量 tempfile。因为模板中的 “X” 字符会被随机字母和 数字代替&#xff0c;所以最终的文件名&#xff08;在这个例子中&#xff0c;文件名也包含了特殊参数 $$ 的展开值&#xff0c;进程的 PID&#xff09;可能像这样&#xff1a;

/tmp/foobar.6593.UOZuvM6654

对于那些由普通用户操作执行的脚本&#xff0c;避免使用 /tmp 目录&#xff0c;而是在用户家目录下为临时文件创建一个目录&#xff0c; 通过像这样的一行代码&#xff1a;

[[ -d $HOME/tmp ]] || mkdir $HOME/tmp



异步执行

有时候需要同时执行多个任务。我们已经知道现在所有的操作系统若不是多用户的但至少是多任务的。 脚本也可以构建成多任务处理的模式。

通常这涉及到启动一个脚本&#xff0c;依次&#xff0c;启动一个或多个子脚本来执行额外的任务&#xff0c;而父脚本继续运行。然而&#xff0c;当一系列脚本 以这种方式运行时&#xff0c;要保持父子脚本之间协调工作&#xff0c;会有一些问题。也就是说&#xff0c;若父脚本或子脚本依赖于另一方&#xff0c;并且 一个脚本必须等待另一个脚本结束任务之后&#xff0c;才能完成它自己的任务&#xff0c;这应该怎么办&#xff1f;

bash 有一个内置命令&#xff0c;能帮助管理诸如此类的异步执行的任务。wait 命令导致一个父脚本暂停运行&#xff0c;直到一个 特定的进程&#xff08;例如&#xff0c;子脚本&#xff09;运行结束。


等待

首先我们将演示一下 wait 命令的用法。为此&#xff0c;我们需要两个脚本&#xff0c;一个父脚本&#xff1a;

#!/bin/bash
# async-parent : Asynchronous execution demo (parent)
echo "Parent: starting..."
echo "Parent: launching child script..."
async-child &
pid&#61;$!
echo "Parent: child (PID&#61; $pid) launched."
echo "Parent: continuing..."
sleep 2
echo "Parent: pausing to wait for child to finish..."
wait $pid
echo "Parent: child is finished. Continuing..."
echo "Parent: parent is done. Exiting."

和一个子脚本&#xff1a;

#!/bin/bash
# async-child : Asynchronous execution demo (child)
echo "Child: child is running..."
sleep 5
echo "Child: child is done. Exiting."

在这个例子中&#xff0c;我们看到该子脚本是非常简单的。真正的操作通过父脚本完成。在父脚本中&#xff0c;子脚本被启动&#xff0c; 并被放置到后台运行。子脚本的进程 ID 记录在 pid 变量中&#xff0c;这个变量的值是 $! shell 参数的值&#xff0c;它总是 包含放到后台执行的最后一个任务的进程 ID 号。

父脚本继续&#xff0c;然后执行一个以子进程 PID 为参数的 wait 命令。这就导致父脚本暂停运行&#xff0c;直到子脚本退出&#xff0c; 意味着父脚本结束。

当执行后&#xff0c;父子脚本产生如下输出&#xff1a;

[me&#64;linuxbox ~]$ async-parent
Parent: starting...
Parent: launching child script...
Parent: child (PID&#61; 6741) launched.
Parent: continuing...
Child: child is running...
Parent: pausing to wait for child to finish...
Child: child is done. Exiting.
Parent: child is finished. Continuing...
Parent: parent is done. Exiting.

命名管道

在大多数类似也 Unix 的操作系统中&#xff0c;有可能创建一种特殊类型的饿文件&#xff0c;叫做命名管道。命名管道用来在 两个进程之间建立连接&#xff0c;也可以像其它类型的文件一样使用。虽然它们不是那么流行&#xff0c;但是它们值得我们去了解。

有一种常见的编程架构&#xff0c;叫做客户端-服务器&#xff0c;它可以利用像命名管道这样的通信方式&#xff0c; 也可以使用其它类型的进程间通信方式&#xff0c;比如网络连接。

最为广泛使用的客户端-服务器系统类型是&#xff0c;当然&#xff0c;一个 web 浏览器与一个 web 服务器之间进行通信。 web 浏览器作为客户端&#xff0c;向服务器发出请求&#xff0c;服务器响应请求&#xff0c;并把对应的网页发送给浏览器。

命令管道的行为类似于文件&#xff0c;但实际上形成了先入先出&#xff08;FIFO&#xff09;的缓冲。和普通&#xff08;未命令的&#xff09;管道一样&#xff0c; 数据从一端进入&#xff0c;然后从另一端出现。通过命令管道&#xff0c;有可能像这样设置一些东西&#xff1a;

process1 > named_pipe

process2

表现出来就像这样&#xff1a;

process1 | process2

设置一个命名管道

首先&#xff0c;我们必须创建一个命名管道。使用 mkfifo 命令能够创建命令管道&#xff1a;

[me&#64;linuxbox ~]$ mkfifo pipe1
[me&#64;linuxbox ~]$ ls -l pipe1
prw-r--r-- 1 me
me
0 2009-07-17 06:41 pipe1

这里我们使用 mkfifo 创建了一个名为 pipe1 的命名管道。使用 ls 命令&#xff0c;我们查看这个文件&#xff0c; 看到位于属性字段的第一个字母是 “p”&#xff0c;表明它是一个命名管道。


使用命名管道

为了演示命名管道是如何工作的&#xff0c;我们将需要两个终端窗口&#xff08;或用两个虚拟控制台代替&#xff09;。 在第一个终端中&#xff0c;我们输入一个简单命令&#xff0c;并把命令的输出重定向到命名管道&#xff1a;

[me&#64;linuxbox ~]$ ls -l > pipe1

我们按下 Enter 按键之后&#xff0c;命令将会挂起。这是因为在管道的另一端没有任何接受数据。当这种现象发生的时候&#xff0c; 据说是管道阻塞了。一旦我们绑定一个进程到管道的另一端&#xff0c;该进程开始从管道中读取输入的时候&#xff0c;这种情况会消失。 使用第二个终端窗口&#xff0c;我们输入这个命令&#xff1a;

[me&#64;linuxbox ~]$ cat

然后产自第一个终端窗口的目录列表出现在第二个终端中&#xff0c;并作为来自 cat 命令的输出。在第一个终端 窗口中的 ls 命令一旦它不再阻塞&#xff0c;会成功地结束。


总结

嗯&#xff0c;我们已经完成了我们的旅程。现在剩下的唯一要做的事就是练习&#xff0c;练习&#xff0c;再练习。 纵然在我们的长途跋涉中&#xff0c;我们涉及了很多命令&#xff0c;但是就命令行而言&#xff0c;我们只是触及了它的表面。 仍留有成千上万的命令行程序&#xff0c;需要去发现和享受。开始挖掘 /usr/bin 目录吧&#xff0c;你将会看到&#xff01;


拓展阅读


  • bash 手册页的 “复合命令” 部分包含了对组命令和子 shell 表示法的详尽描述。

  • bash 手册也的 EXPANSION 部分包含了一小部分进程替换的内容&#xff1a;

  • 《高级 Bash 脚本指南》也有对进程替换的讨论&#xff1a;

    http://tldp.org/LDP/abs/html/process-sub.html

  • 《Linux 杂志》有两篇关于命令管道的好文章。第一篇&#xff0c;源于1997年9月&#xff1a;

    http://www.linuxjournal.com/article/2156

  • 和第二篇&#xff0c;源于2009年3月&#xff1a;

    http://www.linuxjournal.com/content/using-named-pipes-fifos-bash


推荐阅读
  • 本文介绍了在RHEL 7中的系统日志管理和网络管理。系统日志管理包括rsyslog和systemd-journal两种日志服务,分别介绍了它们的特点、配置文件和日志查询方式。网络管理主要介绍了使用nmcli命令查看和配置网络接口的方法,包括查看网卡信息、添加、修改和删除配置文件等操作。 ... [详细]
  • Linux磁盘的分区、格式化的观察和操作步骤
    本文介绍了如何观察Linux磁盘的分区状态,使用lsblk命令列出系统上的所有磁盘列表,并解释了列表中各个字段的含义。同时,还介绍了使用parted命令列出磁盘的分区表类型和分区信息的方法。在进行磁盘分区操作时,根据分区表类型选择使用fdisk或gdisk命令,并提供了具体的分区步骤。通过本文,读者可以了解到Linux磁盘分区和格式化的基本知识和操作步骤。 ... [详细]
  • systemd-nspawn可以创建最轻量级的容器(ns的意思就是namespace),本文的实验平台是Ubuntu16.04,x86_64机器。本文的目的是:在Ubuntu中用syst ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • Webmin远程命令执行漏洞复现及防护方法
    本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]
  • Ubuntu 9.04中安装谷歌Chromium浏览器及使用体验[图文]
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • 初始化初始化本地空版本库,仓库,英文名repositorymkdirtest&&cdtestgitinit克隆项目到本地gitclone远程同 ... [详细]
  • docker安装到基本使用
    记录docker概念,安装及入门日常使用Docker安装查看官方文档,在&quot;Debian上安装Docker&quot;,其他平台在&quot;这里查 ... [详细]
  • 一、概述nmon是一种在AIX与各种Linux操作系统上广泛使用的监控与分析工具,相对于其它一些系统资源监控工具来说,nmon所记录的信息是比较全面的 ... [详细]
author-avatar
白杨树问天
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有