分类 技术 下的文章

本文是 24 天 Linux 桌面特别系列的一部分。如果你是一个觉得传统桌面会妨碍你的极简主义者,那么试试 Pekwm Linux 桌面。

假设你想要一个轻量级桌面环境,它只需要能在屏幕上显示图形、四处移动窗口,而别无杂物。你会发现传统桌面的通知、任务栏和系统托盘会妨碍你的工作。你想主要通过终端工作,但也希望运行图形应用。如果听起来像是你的想法,那么 Pekwm 可能是你一直在寻找的东西。

Pekwm 的灵感大概来自于 Window Maker 和 Fluxbox 等。它提供了一个应用菜单、窗口装饰、而不是一大堆其他东西。它非常适合极简主义者,即那些希望节省资源的用户和喜欢在终端工作的用户。

从发行版仓库安装 Pekwm。安装后,请先退出当前桌面会话,以便可以登录到新桌面。默认情况下,会话管理器(KDM、GDM、LightDM 或 XDM,具体取决于你的设置)将继续登录到以前的桌面,因此需要在登录之前修改它。

在 GDM 中覆盖之前的桌面:

 title=

在 KDM 中:

 title=

第一次登录 Pekwm 时,你可能会看到黑屏。可能难以置信,但这是正常的。你看到的是一个空白桌面,没有背景壁纸。你可以使用 feh 命令设置壁纸(你可能需要从仓库中安装它)。此命令有几个用于设置背景的选项,包括 --bg-fill 用壁纸填充屏幕,--bg-scale 缩放到合适大小,等等。

$ feh --bg-fill ~/Pictures/wallpapers/mybackground.jpg

应用菜单

默认情况下,Pekwm 自动生成一个菜单,可在桌面上的任意位置右键单击,从而可让你运行应用。此菜单还提供一些首选项设置,例如选择主题和注销 Pekwm 会话。

 title=

配置

Pekwm 主要通过保存在 $HOME/.pekwm 下的文本配置文件来配置。menu 文件定义你的应用菜单,keys 文件定义键盘快捷键,等等。

start 文件是在 Pekwm 启动后执行的 shell 脚本。它类似于传统 Unix 系统上的 rc.local。它故意放在最后执行的,因此这里的东西将覆盖之前的一切。这是一个重要文件,它可能是你要设置背景的地方,以便你的选择会覆盖正在使用的主题的默认值。

start 文件也是可以启动 dockapp 的地方。dockapp 是一种小程序,它在 Window Maker 和 Fluxbox 引起了人们的关注。它们通常有网络监视器、时钟、音频设置,和其它你可能会在系统托盘或作为一个 KDE plasmoid 或者完整桌面环境中看到的小部件。你可能会在发行版仓库中找到一些 dockapp,或者可以在 dockapps.net 上在线查找它们。

你可以在启动时运行 dockapp,将它们列在 start 文件中,跟上 & 符号:

feh --bg-fill ~/Pictures/wallpapers/mybackground.jpg
wmnd &
bubblemon -d &

start 文件必须设置为可执行,才能在 Pekwm 启动时运行。

$ chmod +x $HOME/.pekwm/start

功能

Pekwm 的功能不多,但这就是它的美。如果你希望在桌面上运行额外的服务,那么由你来启动这些服务。如果你仍在学习 Linux,这是了解那些与完整的桌面环境捆绑在一起时通常不会注意到的微小 GUI 组件的好方法(像是任务栏)。这也习惯一些 Linux 命令(例如 nmcli)的好方法。

Pekwm 是一个有趣的窗口管理器。它分散、简洁、轻巧。请试试看!


via: https://opensource.com/article/19/12/pekwm-linux-desktop

作者:Seth Kenlon 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

SCP( 安全复制 Secure Copy )是 Linux 和 Unix 之类的系统中的命令行工具,用于通过网络安全地跨系统传输文件和目录。当我们使用 scp 命令将文件和目录从本地系统复制到远程系统时,则在后端与远程系统建立了 ssh 连接。换句话说,我们可以说 scp 在后端使用了相同的 SSH 安全机制,它需要密码或密钥进行身份验证。

在本教程中,我们将讨论 14 个有用的 Linux scp 命令示例。

scp 命令语法:

# scp <选项> <文件或目录> 用户名@目标主机:/<文件夹>

# scp <选项> 用户名@目标主机:/文件 <本地文件夹>

scp 命令的第一个语法演示了如何将文件或目录从本地系统复制到特定文件夹下的目标主机。

scp 命令的第二种语法演示了如何将目标主机中的文件复制到本地系统中。

下面列出了 scp 命令中使用最广泛的一些选项,

  • -C 启用压缩
  • -i 指定识别文件或私钥
  • -l 复制时限制带宽
  • -P 指定目标主机的 ssh 端口号
  • -p 复制时保留文件的权限、模式和访问时间
  • -q 禁止 SSH 警告消息
  • -r 递归复制文件和目录
  • -v 详细输出

现在让我们跳入示例!

示例:1)使用 scp 将文件从本地系统复制到远程系统

假设我们要使用 scp 命令将 jdk 的 rpm 软件包从本地 Linux 系统复制到远程系统(172.20.10.8),请使用以下命令,

[root@linuxtechi ~]$ scp jdk-linux-x64_bin.rpm root@linuxtechi:/opt
root@linuxtechi's password:
jdk-linux-x64_bin.rpm                          100%   10MB  27.1MB/s   00:00
[root@linuxtechi ~]$

上面的命令会将 jdk 的 rpm 软件包文件复制到 /opt 文件夹下的远程系统。

示例:2)使用 scp 将文件从远程系统复制到本地系统

假设我们想将文件从远程系统复制到本地系统下的 /tmp 文件夹,执行以下 scp 命令,

[root@linuxtechi ~]$ scp root@linuxtechi:/root/Technical-Doc-RHS.odt /tmp
root@linuxtechi's password:
Technical-Doc-RHS.odt                         100% 1109KB  31.8MB/s   00:00
[root@linuxtechi ~]$ ls -l /tmp/Technical-Doc-RHS.odt
-rwx------. 1 pkumar pkumar 1135521 Oct 19 11:12 /tmp/Technical-Doc-RHS.odt
[root@linuxtechi ~]$

示例:3)使用 scp 传输文件时的详细输出(-v)

scp 命令中,我们可以使用 -v 选项启用详细输出。使用详细输出,我们可以轻松地发现后台确切发生了什么。这对于调试连接、认证和配置等问题非常有用。

root@linuxtechi ~]$ scp -v jdk-linux-x64_bin.rpm root@linuxtechi:/opt
Executing: program /usr/bin/ssh host 172.20.10.8, user root, command scp -v -t /opt
OpenSSH_7.8p1, OpenSSL 1.1.1 FIPS  11 Sep 2018
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Reading configuration data /etc/ssh/ssh_config.d/05-redhat.conf
debug1: Reading configuration data /etc/crypto-policies/back-ends/openssh.config
debug1: /etc/ssh/ssh_config.d/05-redhat.conf line 8: Applying options for *
debug1: Connecting to 172.20.10.8 [172.20.10.8] port 22.
debug1: Connection established.
…………
debug1: Next authentication method: password
root@linuxtechi's password:

示例:4)将多个文件传输到远程系统

可以使用 scp 命令一次性将多个文件复制/传输到远程系统,在 scp 命令中指定多个文件,并用空格隔开,示例如下所示

[root@linuxtechi ~]$ scp install.txt index.html jdk-linux-x64_bin.rpm root@linuxtechi:/mnt
root@linuxtechi's password:
install.txt                                      100%    0     0.0KB/s   00:00
index.html                                       100%   85KB   7.2MB/s   00:00
jdk-linux-x64_bin.rpm                            100%   10MB  25.3MB/s   00:00
[root@linuxtechi ~]$

示例:5)在两个远程主机之间传输文件

使用 scp 命令,我们可以在两个远程主机之间复制文件和目录,假设我们有一个可以连接到两个远程 Linux 系统的本地 Linux 系统,因此从我的本地 Linux 系统中,我可以使用 scp 命令在这两个系统之间复制文件,

命令语法:

# scp 用户名@远程主机1:/<要传输的文件> 用户名@远程主机2:/<文件夹>

示例如下:

# scp root@linuxtechi:~/backup-Oct.zip root@linuxtechi:/tmp
# ssh root@linuxtechi "ls -l /tmp/backup-Oct.zip"
-rwx------. 1 root root 747438080 Oct 19 12:02 /tmp/backup-Oct.zip

示例:6)递归复制文件和目录(-r)

scp 命令中使用 -r 选项将整个目录从一个系统递归地复制到另一个系统,示例如下所示:

[root@linuxtechi ~]$ scp -r Downloads root@linuxtechi:/opt

使用以下命令验证 Downloads 文件夹是否已复制到远程系统,

[root@linuxtechi ~]$ ssh root@linuxtechi "ls -ld /opt/Downloads"
drwxr-xr-x. 2 root root 75 Oct 19 12:10 /opt/Downloads
[root@linuxtechi ~]$

示例:7)通过启用压缩来提高传输速度(-C)

scp 命令中,我们可以通过使用 -C 选项启用压缩来提高传输速度,它将自动在源主机上启用压缩并在目标主机上解压缩。

root@linuxtechi ~]$ scp -r -C Downloads root@linuxtechi:/mnt

在以上示例中,我们正在启用压缩的情况下传输下载目录。

示例:8)复制时限制带宽(-l)

scp 命令中使用 -l 选项设置复制时对带宽使用的限制。带宽以 Kbit/s 为单位指定,示例如下所示:

[root@linuxtechi ~]$ scp -l 500 jdk-linux-x64_bin.rpm  root@linuxtechi:/var

示例:9)在 scp 时指定其他 ssh 端口(-P)

在某些情况下,目标主机上的 ssh 端口会更改,因此在使用 scp 命令时,我们可以使用 -P 选项指定 ssh 端口号。

[root@linuxtechi ~]$ scp -P 2022 jdk-linux-x64_bin.rpm  root@linuxtechi:/var

在上面的示例中,远程主机的 ssh 端口为 “2022”。

示例:10)复制时保留文件的权限、模式和访问时间(-p)

从源复制到目标时,在 scp 命令中使用 -p 选项保留权限、访问时间和模式。

[root@linuxtechi ~]$ scp -p jdk-linux-x64_bin.rpm  root@linuxtechi:/var/tmp
jdk-linux-x64_bin.rpm                            100%   10MB  13.5MB/s   00:00
[root@linuxtechi ~]$

示例:11)在 scp 中以安静模式传输文件(-q)

scp 命令中使用 -q 选项可禁止显示 ssh 的传输进度、警告和诊断消息。示例如下所示:

[root@linuxtechi ~]$ scp -q -r Downloads root@linuxtechi:/var/tmp
[root@linuxtechi ~]$

示例:12)在传输时使用 scp 中的识别文件(-i)

在大多数 Linux 环境中,首选基于密钥的身份验证。在 scp 命令中,我们使用 -i 选项指定识别文件(私钥文件),示例如下所示:

[root@linuxtechi ~]$ scp -i my_key.pem -r Downloads root@linuxtechi:/root

在上面的示例中,my_key.pem 是识别文件或私钥文件。

示例:13)在 scp 中使用其他 ssh\_config 文件(-F)

在某些情况下,你使用不同的网络连接到 Linux 系统,可能某些网络位于代理服务器后面,因此在这种情况下,我们必须具有不同的 ssh_config 文件。

通过 -F 选项在 scp 命令中指定了不同的 ssh_config 文件,示例如下所示:

[root@linuxtechi ~]$ scp -F /home/pkumar/new_ssh_config -r Downloads root@linuxtechi:/root
root@linuxtechi's password:
jdk-linux-x64_bin.rpm                     100%   10MB  16.6MB/s   00:00
backup-Oct.zip                            100%  713MB  41.9MB/s   00:17
index.html                                100%   85KB   6.6MB/s   00:00
[root@linuxtechi ~]$

示例:14)在 scp 命令中使用其他加密方式(-c)

默认情况下,scp 使用 AES-128 加密方式来加密文件。如果你想在 scp 命令中使用其他加密方式,请使用 -c 选项,后接加密方式名称。

假设我们要在用 scp 命令传输文件时使用 3des-cbc 加密方式,请运行以下 scp 命令:

[root@linuxtechi ~]# scp -c 3des-cbc -r Downloads root@linuxtechi:/root

使用以下命令列出 sshscp 支持的加密方式:

[root@linuxtechi ~]# ssh -Q cipher localhost | paste -d , -s -
3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,root@linuxtechi,aes128-ctr,aes192-ctr,aes256-ctr,root@linuxtechi,root@linuxtechi,root@linuxtechi
[root@linuxtechi ~]#

以上就是本教程的全部内容,要获取有关 scp 命令的更多详细信息,请参考其手册页。请在下面的评论部分中分享你的反馈和评论。


via: https://www.linuxtechi.com/scp-command-examples-in-linux/

作者:Pradeep Kumar 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

我的大部分工作都涉及到部署软件系统,这意味着我需要花费很多时间来解决以下问题:

  • 这个软件可以在原开发者的机器上工作,但是为什么不能在我这里运行?
  • 这个软件昨天可以在我的机器上工作,但是为什么今天就不行?

这是一种调试的类型,但是与一般的软件调试有所不同。一般的调试通常只关心代码的逻辑,但是在软件部署中的调试关注的是程序的代码和它所在的运行环境之间的相互影响。即便问题的根源是代码的逻辑错误,但软件显然可以在别的机器上运行的事实意味着这类问题与运行环境密切相关。

所以,在软件部署过程中,我没有使用传统的调试工具(例如 gdb),而是选择了其它工具进行调试。我最喜欢的用来解决“为什么这个软件无法在这台机器上运行?”这类问题的工具就是 strace

什么是 strace?

strace 是一个用来“追踪系统调用”的工具。它主要是一个 Linux 工具,但是你也可以在其它系统上使用类似的工具(例如 DTracektrace)。

它的基本用法非常简单。只需要在 strace 后面跟上你需要运行的命令,它就会显示出该命令触发的所有系统调用(你可能需要先安装好 strace):

$ strace echo Hello
...Snip lots of stuff...
write(1, "Hello\n", 6)                  = 6
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

这些系统调用都是什么?它们就像是操作系统内核提供的 API。很久以前,软件拥有直接访问硬件的权限。如果软件需要在屏幕上显示一些东西,它将会与视频硬件的端口和内存映射寄存器纠缠不清。当多任务操作系统变得流行以后,这就导致了混乱的局面,因为不同的应用程序将“争夺”硬件,并且一个应用程序的错误可能致使其它应用程序崩溃,甚至导致整个系统崩溃。所以 CPU 开始支持多种不同的特权模式(或者称为“保护环”)。它们让操作系统内核在具有完全硬件访问权限的最高特权模式下运行,于此同时,其它在低特权模式下运行的应用程序必须通过向内核发起系统调用才能够与硬件进行交互。

在二进制级别上,发起系统调用相比简单的函数调用有一些区别,但是大部分程序都使用标准库提供的封装函数。例如,POSIX C 标准库包含一个 write() 函数,该函数包含用于进行 write 系统调用的所有与硬件体系结构相关的代码。

简单来说,一个应用程序与其环境(计算机系统)的交互都是通过系统调用来完成的。所以当软件在一台机器上可以工作但是在另一台机器无法工作的时候,追踪系统调用是一个很好的查错方法。具体地说,你可以通过追踪系统调用分析以下典型操作:

  • 控制台输入与输出 (IO)
  • 网络 IO
  • 文件系统访问以及文件 IO
  • 进程/线程生命周期管理
  • 原始内存管理
  • 访问特定的设备驱动

什么时候可以使用 strace?

理论上,strace 适用于任何用户空间程序,因为所有的用户空间程序都需要进行系统调用。strace 对于已编译的低级程序最有效果,但如果你可以避免运行时环境和解释器带来的大量额外输出,则仍然可以与 Python 等高级语言程序一起使用。

当软件在一台机器上正常工作,但在另一台机器上却不能正常工作,同时抛出了有关文件、权限或者不能运行某某命令等模糊的错误信息时,strace 往往能大显身手。不幸的是,它不能诊断高等级的问题,例如数字证书验证错误等。这些问题通常需要组合使用 strace(有时候是 ltrace)和其它高级工具(例如使用 openssl 命令行工具调试数字证书错误)。

本文中的示例基于独立的服务器,但是对系统调用的追踪通常也可以在更复杂的部署平台上完成,仅需要找到合适的工具。

一个简单的例子

假设你正在尝试运行一个叫做 foo 的服务器应用程序,但是发生了以下情况:

$ foo
Error opening configuration file: No such file or directory

显然,它没有找到你已经写好的配置文件。之所以会发生这种情况,是因为包管理工具有时候在编译应用程序时指定了自定义的路径,所以你应当遵循特定发行版提供的安装指南。如果错误信息告诉你正确的配置文件应该在什么地方,你就可以在几秒钟内解决这个问题,但如果没有告诉你呢?你该如何找到正确的路径?

如果你有权访问源代码,则可以通过阅读源代码来解决问题。这是一个好的备用计划,但不是最快的解决方案。你还可以使用类似 gdb 的单步调试器来观察程序的行为,但使用专门用于展示程序与系统环境交互作用的工具 strace 更加有效。

一开始, strace 产生的大量输出可能会让你不知所措,幸好你可以忽略其中大部分的无用信息。我经常使用 -o 参数把输出的追踪结果保存到单独的文件里:

$ strace -o /tmp/trace foo
Error opening configuration file: No such file or directory
$ cat /tmp/trace
execve("foo", ["foo"], 0x7ffce98dc010 /* 16 vars */) = 0
brk(NULL)                               = 0x56363b3fb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=25186, ...}) = 0
mmap(NULL, 25186, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2f12cf1000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260A\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1824496, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2f12cef000
mmap(NULL, 1837056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2f12b2e000
mprotect(0x7f2f12b50000, 1658880, PROT_NONE) = 0
mmap(0x7f2f12b50000, 1343488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f2f12b50000
mmap(0x7f2f12c98000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16a000) = 0x7f2f12c98000
mmap(0x7f2f12ce5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7f2f12ce5000
mmap(0x7f2f12ceb000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2f12ceb000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f2f12cf0500) = 0
mprotect(0x7f2f12ce5000, 16384, PROT_READ) = 0
mprotect(0x56363b08b000, 4096, PROT_READ) = 0
mprotect(0x7f2f12d1f000, 4096, PROT_READ) = 0
munmap(0x7f2f12cf1000, 25186)           = 0
openat(AT_FDCWD, "/etc/foo/config.json", O_RDONLY) = -1 ENOENT (No such file or directory)
dup(2)                                  = 3
fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
brk(NULL)                               = 0x56363b3fb000
brk(0x56363b41c000)                     = 0x56363b41c000
fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x8), ...}) = 0
write(3, "Error opening configuration file"..., 60) = 60
close(3)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++

strace 输出的第一页通常是低级的进程启动过程。(你可以看到很多 mmapmprotectbrk 调用,这是用来分配原始内存和映射动态链接库的。)实际上,在查找错误时,最好从下往上阅读 strace 的输出。你可以看到 write 调用在最后返回了错误信息。如果你向上找,你将会看到第一个失败的系统调用是 openat,它在尝试打开 /etc/foo/config.json 时抛出了 ENOENT (“No such file or directory”)的错误。现在我们已经知道了配置文件应该放在哪里。

这是一个简单的例子,但我敢说在 90% 的情况下,使用 strace 进行调试不需要更多复杂的工作。以下是完整的调试步骤:

  1. 从程序中获得含糊不清的错误信息
  2. 使用 strace 运行程序
  3. 在输出中找到错误信息
  4. 往前追溯并找到第一个失败的系统调用

第四步中的系统调用很可能向你显示出问题所在。

小技巧

在开始更加复杂的调试之前,这里有一些有用的调试技巧帮助你高效使用 strace

man 是你的朋友

在很多 *nix 操作系统中,你可以通过 man syscalls 查看系统调用的列表。你将会看到类似于 brk(2) 之类的东西,这意味着你可以通过运行 man 2 brk 得到与此相关的更多信息。

一个小问题:man 2 fork 会显示出在 GNU libc 里封装的 fork() 手册页,而 fork() 现在实际上是由 clone 系统调用实现的。fork 的语义与 clone 相同,但是如果我写了一个含有 fork() 的程序并使用 strace 去调试它,我将找不到任何关于 fork 调用的信息,只能看到 clone 调用。如果将源代码与 strace 的输出进行比较的时候,像这种问题会让人感到困惑。

使用 -o 将输出保存到文件

strace 可以生成很多输出,所以将输出保存到单独的文件是很有帮助的(就像上面的例子一样)。它还能够在控制台中避免程序自身的输出与 strace 的输出发生混淆。

使用 -s 查看更多的参数

你可能已经注意到,错误信息的第二部分没有出现在上面的例子中。这是因为 strace 默认仅显示字符串参数的前 32 个字节。如果你需要捕获更多参数,请向 strace 追加类似于 -s 128 之类的参数。

-y 使得追踪文件或套接字更加容易

“一切皆文件”意味着 *nix 系统通过文件描述符进行所有 IO 操作,不管是真实的文件还是通过网络或者进程间管道。这对于编程而言是很方便的,但是在追踪系统调用时,你将很难分辨出 readwrite 的真实行为。

-y 参数使 strace 在注释中注明每个文件描述符的具体指向。

使用 -p 附加到正在运行的进程中

正如我们将在后面的例子中看到的,有时候你想追踪一个正在运行的程序。如果你知道这个程序的进程号为 1337 (可以通过 ps 查询),则可以这样操作:

$ strace -p 1337
...system call trace output...

你可能需要 root 权限才能运行。

使用 -f 追踪子进程

strace 默认只追踪一个进程。如果这个进程产生了一个子进程,你将会看到创建子进程的系统调用(一般是 clone),但是你看不到子进程内触发的任何调用。

如果你认为在子进程中存在错误,则需要使用 -f 参数启用子进程追踪功能。这样做的缺点是输出的内容会让人更加困惑。当追踪一个进程时,strace 显示的是单个调用事件流。当追踪多个进程的时候,你将会看到以 <unfinished ...> 开始的初始调用,接着是一系列针对其它线程的调用,最后才出现以 <... foocall resumed> 结束的初始调用。此外,你可以使用 -ff 参数将所有的调用分离到不同的文件中(查看 strace 手册 获取更多信息)。

使用 -e 进行过滤

正如你所看到的,默认的追踪输出是所有的系统调用。你可以使用 -e 参数过滤你需要追踪的调用(查看 strace 手册)。这样做的好处是运行过滤后的 strace 比起使用 grep 进行二次过滤要更快。老实说,我大部分时间都不会被打扰。

并非所有的错误都是不好的

一个简单而常用的例子是一个程序在多个位置搜索文件,例如 shell 搜索哪个 bin/ 目录包含可执行文件:

$ strace sh -c uname
...
stat("/home/user/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory)
stat("/usr/bin/uname", {st_mode=S_IFREG|0755, st_size=39584, ...}) = 0
...

“错误信息之前的最后一次失败调用”这种启发式方法非常适合于查找错误。无论如何,自下而上地查找是有道理的。

C 编程指南非常有助于理解系统调用

标准 C 库函数调用不属于系统调用,但它们仅是系统调用之上的唯一一个薄层。所以如果你了解(甚至只是略知一二)如何使用 C 语言,那么阅读系统调用追踪信息就非常容易。例如,如果你在调试网络系统调用,你可以尝试略读 Beej 经典的《网络编程指南》

一个更复杂的调试例子

就像我说的那样,简单的调试例子表现了我在大部分情况下如何使用 strace。然而,有时候需要一些更加细致的工作,所以这里有一个稍微复杂(且真实)的例子。

bcron 是一个任务调度器,它是经典 *nix cron 守护程序的另一种实现。它已经被安装到一台服务器上,但是当有人尝试编辑作业时间表时,发生了以下情况:

# crontab -e -u logs
bcrontab: Fatal: Could not create temporary file

好的,现在 bcron 尝试写入一些文件,但是它失败了,也没有告诉我们原因。以下是 strace 的输出:

# strace -o /tmp/trace crontab -e -u logs
bcrontab: Fatal: Could not create temporary file
# cat /tmp/trace
...
openat(AT_FDCWD, "bcrontab.14779.1573691864.847933", O_RDONLY) = 3
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
read(3, "#Ansible: logsagg\n20 14 * * * lo"..., 8192) = 150
read(3, "", 8192)                       = 0
munmap(0x7f82049b4000, 8192)            = 0
close(3)                                = 0
socket(AF_UNIX, SOCK_STREAM, 0)         = 3
connect(3, {sa_family=AF_UNIX, sun_path="/var/run/bcron-spool"}, 110) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000
write(3, "156:Slogs\0#Ansible: logsagg\n20 1"..., 161) = 161
read(3, "32:ZCould not create temporary f"..., 8192) = 36
munmap(0x7f82049b4000, 8192)            = 0
close(3)                                = 0
write(2, "bcrontab: Fatal: Could not creat"..., 49) = 49
unlink("bcrontab.14779.1573691864.847933") = 0
exit_group(111)                         = ?
+++ exited with 111 +++

在程序结束之前有一个 write 的错误信息,但是这次有些不同。首先,在此之前没有任何相关的失败系统调用。其次,我们看到这个错误信息是由 read 从别的地方读取而来的。这看起来像是真正的错误发生在别的地方,而 bcrontab 只是在转播这些信息。

如果你查阅了 man 2 read,你将会看到 read 的第一个参数 (3) 是一个文件描述符,这是 *nix 操作系统用于所有 IO 操作的句柄。你该如何知道文件描述符 3 代表什么?在这种情况下,你可以使用 -y 参数运行 strace(如上文所述),它将会在注释里告诉你文件描述符的具体指向,但是了解如何从上面这种输出中分析追踪结果是很有用的。

一个文件描述符可以来自于许多系统调用之一(这取决于它是用于控制台、网络套接字还是真实文件等的描述符),但不论如何,我们都可以搜索返回值为 3 的系统调用(例如,在 strace 的输出中查找 =3)。在这次 strace 中可以看到有两个这样的调用:最上面的 openat 以及中间的 socketopenat 打开一个文件,但是紧接着的 close(3) 表明其已经被关闭。(注意:文件描述符可以在打开并关闭后重复使用。)所以 socket 调用才是与此相关的(它是在 read 之前的最后一个),这告诉我们 brcontab 正在与一个网络套接字通信。在下一行,connect 表明文件描述符 3 是一个连接到 /var/run/bcron-spool 的 Unix 域套接字。

因此,我们需要弄清楚 Unix 套接字的另一侧是哪个进程在监听。有两个巧妙的技巧适用于在服务器部署中调试。一个是使用 netstat 或者较新的 ss。这两个命令都描述了当前系统中活跃的网络套接字,使用 -l 参数可以显示出处于监听状态的套接字,而使用 -p 参数可以得到正在使用该套接字的程序信息。(它们还有更多有用的选项,但是这两个已经足够完成工作了。)

# ss -pl | grep /var/run/bcron-spool
u_str LISTEN 0   128   /var/run/bcron-spool 1466637   * 0   users:(("unixserver",pid=20629,fd=3))

这告诉我们 /var/run/bcron-spool 套接字的监听程序是 unixserver 这个命令,它的进程 ID 为 20629。(巧合的是,这个程序也使用文件描述符 3 去连接这个套接字。)

第二个常用的工具就是使用 lsof 查找相同的信息。它可以列出当前系统中打开的所有文件(或文件描述符)。或者,我们可以得到一个具体文件的信息:

# lsof /var/run/bcron-spool
COMMAND   PID   USER  FD  TYPE  DEVICE              SIZE/OFF  NODE    NAME
unixserve 20629 cron  3u  unix  0x000000005ac4bd83  0t0       1466637 /var/run/bcron-spool type=STREAM

进程 20629 是一个常驻进程,所以我们可以使用 strace -o /tmp/trace -p 20629 去查看该进程的系统调用。如果我们在另一个终端尝试编辑 cron 的计划任务表,就可以在错误发生时捕获到以下信息:

accept(3, NULL, NULL)                   = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21181
close(4)                                = 0
accept(3, NULL, NULL)                   = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21181, si_uid=998, si_status=0, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED, NULL) = 21181
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]})                 = 43
accept(3, NULL, NULL)                   = 4
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21200
close(4)                                = 0
accept(3, NULL, NULL)                   = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21200, si_uid=998, si_status=111, si_utime=0, si_stime=0} ---
wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 111}], WNOHANG|WSTOPPED, NULL) = 21200
wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0
rt_sigreturn({mask=[]})                 = 43
accept(3, NULL, NULL

(最后一个 accept 调用没有在追踪期间完成。)不幸的是,这次追踪没有包含我们想要的错误信息。我们没有观察到 bcrontan 往套接字发送或接受的任何信息。然而,我们看到了很多进程管理操作(clonewait4SIGCHLD,等等)。这个进程产生了子进程,我们猜测真实的工作是由子进程完成的。如果我们想捕获子进程的追踪信息,就必须往 strace 追加 -f 参数。以下是我们最终使用 strace -f -o /tmp/trace -p 20629 找到的错误信息:

21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied)
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111)                   = ?
21470 +++ exited with 111 +++

现在我们知道了进程 ID 21470 在尝试创建文件 tmp/spool.21470.1573692319.854640 (相对于当前的工作目录)时得到了一个没有权限的错误。如果我们知道当前的工作目录,就可以得到完整路径并能指出为什么该进程无法在此处创建临时文件。不幸的是,这个进程已经退出了,所以我们不能使用 lsof -p 21470 去找出当前的工作目录,但是我们可以往前追溯,查找进程 ID 21470 使用哪个系统调用改变了它的工作目录。这个系统调用是 chdir(可以在搜索引擎很轻松地找到)。以下是一直往前追溯到服务器进程 ID 20629 的结果:

20629 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21470
...
21470 execve("/usr/sbin/bcron-spool", ["bcron-spool"], 0x55d2460807e0 /* 27 vars */) = 0
...
21470 chdir("/var/spool/cron")          = 0
...
21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied)
21470 write(1, "32:ZCould not create temporary f"..., 36) = 36
21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84
21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory)
21470 exit_group(111)                   = ?
21470 +++ exited with 111 +++

(如果你在这里迷糊了,你可能需要阅读 我之前有关 *nix 进程管理和 shell 的文章

现在 PID 为 20629 的服务器进程没有权限在 /var/spool/cron/tmp/spool.21470.1573692319.854640 创建文件。最可能的原因就是典型的 *nix 文件系统权限设置。让我们检查一下:

# ls -ld /var/spool/cron/tmp/
drwxr-xr-x 2 root root 4096 Nov  6 05:33 /var/spool/cron/tmp/
# ps u -p 20629
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
cron     20629  0.0  0.0   2276   752 ?        Ss   Nov14   0:00 unixserver -U /var/run/bcron-spool -- bcron-spool

这就是问题所在!这个服务进程以 cron 用户运行,但是只有 root 用户才有向 /var/spool/cron/tmp/ 目录写入的权限。一个简单 chown cron /var/spool/cron/tmp/ 命令就能让 bcron 正常工作。(如果不是这个问题,那么下一个最有可能的怀疑对象是诸如 SELinux 或者 AppArmor 之类的内核安全模块,因此我将会使用 dmesg 检查内核日志。)

总结

最初,系统调用追踪可能会让人不知所措,但是我希望我已经证明它们是调试一整套常见部署问题的快速方法。你可以设想一下尝试用单步调试器去调试多进程的 bcron 问题。

通过一连串的系统调用解决问题是需要练习的,但正如我说的那样,在大多数情况下,我只需要使用 strace 从下往上追踪并查找错误。不管怎样,strace 节省了我很多的调试时间。我希望这也对你有所帮助。


via: https://theartofmachinery.com/2019/11/14/deployment_debugging_strace.html

作者:Simon Arneaud 选题:lujun9972 译者:hanwckf 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

学习怎样使用 awk 的 !visited[$0]++ 在不重新排序或改变原排列顺序的前提下删掉重复的行。

假设你有一个文本文件,你需要删掉所有重复的行。

TL;DR

要保持原来的排列顺序删掉重复行,使用:

awk '!visited[$0]++' your_file > deduplicated_file

工作原理

这个脚本维护一个关联数组,索引(键)为文件中去重后的行,每个索引对应的值为该行出现的次数。对于文件的每一行,如果这行(之前)出现的次数为 0,则值加 1,并打印这行,否则值加 1,不打印这行。

我之前不熟悉 awk,我想弄清楚这么短小的一个脚本是怎么实现的。我调研了下,下面是调研心得:

  • 这个 awk “脚本” !visited[$0]++ 对输入文件的每一行都执行。
  • visited[] 是一个关联数组(又名映射)类型的变量。awk 会在第一次执行时初始化它,因此我们不需要初始化。
  • $0 变量的值是当前正在被处理的行的内容。
  • visited[$0] 通过与 $0(正在被处理的行)相等的键来访问该映射中的值,即出现次数(我们在下面设置的)。
  • ! 对表示出现次数的值取反:

    • awk 中,任意非零的数或任意非空的字符串的值是 true
    • 变量默认的初始值为空字符串,如果被转换为数字,则为 0。
    • 也就是说:

      • 如果 visited[$0] 的值是一个比 0 大的数,取反后被解析成 false
      • 如果 visited[$0] 的值为等于 0 的数字或空字符串,取反后被解析成 true
    • ++ 表示变量 visited[$0] 的值加 1。

      • 如果该值为空,awk 自动把它转换为 0(数字) 后加 1。
      • 注意:加 1 操作是在我们取到了变量的值之后执行的。

总的来说,整个表达式的意思是:

  • true:如果表示出现次数为 0 或空字符串
  • false:如果出现的次数大于 0

awk模式或表达式和一个与之关联的动作 组成:

<模式/表达式> { <动作> }

如果匹配到了模式,就会执行后面的动作。如果省略动作,awk 默认会打印(print)输入。

省略动作等价于 {print $0}

我们的脚本由一个 awk 表达式语句组成,省略了动作。因此这样写:

awk '!visited[$0]++' your_file > deduplicated_file

等于这样写:

awk '!visited[$0]++ { print $0 }' your_file > deduplicated_file

对于文件的每一行,如果表达式匹配到了,这行内容被打印到输出。否则,不执行动作,不打印任何东西。

为什么不用 uniq 命令?

uniq 命令仅能对相邻的行去重。这是一个示例:

$ cat test.txt
A
A
A
B
B
B
A
A
C
C
C
B
B
A
$ uniq < test.txt
A
B
A
C
B
A

其他方法

使用 sort 命令

我们也可以用下面的 sort 命令来去除重复的行,但是原来的行顺序没有被保留

sort -u your_file > sorted_deduplicated_file

使用 cat + sort + cut

上面的方法会产出一个去重的文件,各行是基于内容进行排序的。通过管道连接命令可以解决这个问题。

cat -n your_file | sort -uk2 | sort -nk1 | cut -f2-

工作原理

假设我们有下面一个文件:

abc
ghi
abc
def
xyz
def
ghi
klm

cat -n test.txt 在每行前面显示序号:

1       abc
2       ghi
3       abc
4       def
5       xyz
6       def
7       ghi
8       klm

sort -uk2 基于第二列(k2 选项)进行排序,对于第二列相同的值只保留一次(u 选项):

1       abc
4       def
2       ghi
8       klm
5       xyz

sort -nk1 基于第一列排序(k1 选项),把列的值作为数字来处理(-n 选项):

1       abc
2       ghi
4       def
5       xyz
8       klm

最后,cut -f2- 从第二列开始打印每一行,直到最后的内容(-f2- 选项:留意 - 后缀,它表示这行后面的内容都包含在内)。

abc
ghi
def
xyz
klm

参考

以上为全文。


via: https://opensource.com/article/19/10/remove-duplicate-lines-files-awk

作者:Lazarus Lazaridis 选题:lujun9972 译者:lxbwolf 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

当你需要在 shell 脚本中创建邮件时,就需要用到命令行发送邮件的知识。Linux 中有很多命令可以实现发送邮件。本教程中包含了最流行的 5 个命令行邮件客户端,你可以选择其中一个。这 5 个命令分别是:

  • mail / mailx
  • mutt
  • mpack
  • sendmail
  • ssmtp

工作原理

我先从整体上来解释下 Linux 中邮件命令怎么把邮件传递给收件人的。邮件命令撰写邮件并发送给一个本地邮件传输代理(MTA,如 sendmail、Postfix)。邮件服务器和远程邮件服务器之间通信以实际发送和接收邮件。下面的流程可以看得更详细。

1) 如何在 Linux 上安装 mail/mailx 命令

mail 命令是 Linux 终端发送邮件用的最多的命令。mailxmail 命令的更新版本,基于 Berkeley Mail 8.1,意在提供 POSIX mailx 命令的功能,并支持 MIME、IMAP、POP3、SMTP 和 S/MIME 扩展。mailx 在某些交互特性上更加强大,如缓冲邮件消息、垃圾邮件评分和过滤等。在 Linux 发行版上,mail 命令是 mailx 命令的软链接。可以运行下面的命令从官方发行版仓库安装 mail 命令。

对于 Debian/Ubuntu 系统,使用 APT-GET 命令APT 命令 安装 mailutils。

$ sudo apt-get install mailutils

对于 RHEL/CentOS 系统,使用 YUM 命令 安装 mailx。

$ sudo yum install mailx

对于 Fedora 系统,使用 DNF 命令 安装 mailx。

$ sudo dnf install mailx

1a) 如何在 Linux 上使用 mail 命令发送邮件

mail 命令简单易用。如果你不需要发送附件,使用下面的 mail 命令格式就可以发送邮件了:

$ echo "This is the mail body" | mail -s "Subject" [email protected]

如果你要发送附件,使用下面的 mail 命令格式:

$ echo "This is the mail body" | mail -a test1.txt -s "Subject" [email protected]
  • -a:用于在基于 Red Hat 的系统上添加附件。
  • -A:用于在基于 Debian 的系统上添加附件。
  • -s:指定消息标题。

2) 如何在 Linux 上安装 mutt 命令

mutt 是另一个很受欢迎的在 Linux 终端发送邮件的命令。mutt 是一个小而强大的基于文本的程序,用来在 unix 操作系统下阅读和发送电子邮件,并支持彩色终端、MIME、OpenPGP 和按邮件线索排序的模式。可以运行下面的命令从官方发行版仓库安装 mutt 命令。

对于 Debian/Ubuntu 系统,使用 APT-GET 命令APT 命令 安装 mutt。

$ sudo apt-get install mutt

对于 RHEL/CentOS 系统,使用 YUM 命令 安装 mutt。

$ sudo yum install mutt

对于 Fedora 系统,使用 DNF 命令 安装 mutt。

$ sudo dnf install mutt

2b) 如何在 Linux 上使用 mutt 命令发送邮件

mutt 一样简单易用。如果你不需要发送附件,使用下面的 mutt 命令格式就可以发送邮件了:

$ echo "This is the mail body" | mutt -s "Subject" [email protected]

如果你要发送附件,使用下面的 mutt 命令格式:

$ echo "This is the mail body" | mutt -s "Subject" [email protected] -a test1.txt

3) 如何在 Linux 上安装 mpack 命令

mpack 是另一个很受欢迎的在 Linux 终端上发送邮件的命令。mpack 程序会在一个或多个 MIME 消息中对命名的文件进行编码。编码后的消息被发送到一个或多个收件人。可以运行下面的命令从官方发行版仓库安装 mpack 命令。

对于 Debian/Ubuntu 系统,使用 APT-GET 命令APT 命令 安装 mpack。

$ sudo apt-get install mpack

对于 RHEL/CentOS 系统,使用 YUM 命令 安装 mpack。

$ sudo yum install mpack

对于 Fedora 系统,使用 DNF 命令 安装 mpack。

$ sudo dnf install mpack

3a) 如何在 Linux 上使用 mpack 命令发送邮件

mpack 同样简单易用。如果你不需要发送附件,使用下面的 mpack 命令格式就可以发送邮件了:

$ echo "This is the mail body" | mpack -s "Subject" [email protected]

如果你要发送附件,使用下面的 mpack 命令格式:

$ echo "This is the mail body" | mpack -s "Subject" [email protected] -a test1.txt

4) 如何在 Linux 上安装 sendmail 命令

sendmail 是一个上广泛使用的通用 SMTP 服务器,你也可以从命令行用 sendmail 发邮件。可以运行下面的命令从官方发行版仓库安装 sendmail 命令。

对于 Debian/Ubuntu 系统,使用 APT-GET 命令APT 命令安装 sendmail。

$ sudo apt-get install sendmail

对于 RHEL/CentOS 系统,使用 YUM 命令 安装 sendmail。

$ sudo yum install sendmail

对于 Fedora 系统,使用 DNF 命令 安装 sendmail。

$ sudo dnf install sendmail

4a) 如何在 Linux 上使用 sendmail 命令发送邮件

sendmail 同样简单易用。使用下面的 sendmail 命令发送邮件。

$ echo -e "Subject: Test Mail\nThis is the mail body" > /tmp/send-mail.txt
$ sendmail [email protected] < send-mail.txt

5) 如何在 Linux 上安装 ssmtp 命令

ssmtp 是类似 sendmail 的一个只发送不接收的工具,可以把邮件从本地计算机传递到配置好的 邮件主机(mailhub)。用户可以在 Linux 命令行用 ssmtp 把邮件发送到 SMTP 服务器。可以运行下面的命令从官方发行版仓库安装 ssmtp 命令。

对于 Debian/Ubuntu 系统,使用 APT-GET 命令APT 命令安装 ssmtp。

$ sudo apt-get install ssmtp

对于 RHEL/CentOS 系统,使用 YUM 命令 安装 ssmtp。

$ sudo yum install ssmtp

对于 Fedora 系统,使用 DNF 命令 安装 ssmtp。

$ sudo dnf install ssmtp

5a) 如何在 Linux 上使用 ssmtp 命令发送邮件

ssmtp 同样简单易用。使用下面的 ssmtp 命令格式发送邮件。

$ echo -e "Subject: Test Mail\nThis is the mail body" > /tmp/ssmtp-mail.txt
$ ssmtp [email protected] < /tmp/ssmtp-mail.txt

via: https://www.2daygeek.com/6-ways-to-send-email-from-the-linux-command-line/

作者:Magesh Maruthamuthu 选题:lujun9972 译者:lxbwolf 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

本教程教你怎样在 Linux 终端快速检测一个网站是否宕机。

你可能已经了解了一些类似的命令,像 pingcurlwget。我们在本教程中又加入了一些其他命令。同时,我们也加入了不同的选项来检测单个和多个主机的信息。

本文将帮助你检测网站是否宕机。但是如果你在维护一些网站,希望网站宕掉时得到实时的报警,我推荐你去使用实时网站监控工具。这种工具有很多,有些是免费的,大部分收费。根据你的需求,选择合适的工具。在后续的文章中我们会涉及这个主题。

方法 1:使用 fping 命令检测一个网站是否宕机

fping 命令 是一个类似 ping 的程序,使用互联网控制消息协议(ICMP)的 回应请求报文 echo request 来判断目标主机是否能回应。fpingping 的不同之处在于它可以并行地 ping 任意数量的主机,也可以从一个文本文件读入主机名称。fping 发送一个 ICMP 回应请求后不等待目标主机响应,就以轮询模式向下一个目标主机发请求。如果一个目标主机有响应,那么它就被标记为存活的,然后从检查目标列表里去掉。如果一个目标主机在限定的时间和(或)重试次数内没有响应,则被指定为网站无法到达的。

# fping 2daygeek.com linuxtechnews.com magesh.co.in

2daygeek.com is alive
linuxtechnews.com is alive
magesh.co.in is alive

方法 2:使用 http 命令检测一个网站是否宕机

HTTPie(读作 aitch-tee-tee-pie)是一个命令行 HTTP 客户端。httpie 是一个可以与 web 服务通过 CLI 进行交互的现代工具。httpie 工具提供了简单的 http 命令,可以通过发送简单的、自然语言语法的任意 HTTP 请求得到多彩的结果输出。HTTPie 可以用来对 HTTP 服务器进行测试、调试和基本的交互。

# http 2daygeek.com

HTTP/1.1 301 Moved Permanently
CF-RAY: 535b66722ab6e5fc-LHR
Cache-Control: max-age=3600
Connection: keep-alive
Date: Thu, 14 Nov 2019 19:30:28 GMT
Expires: Thu, 14 Nov 2019 20:30:28 GMT
Location: https://2daygeek.com/
Server: cloudflare
Transfer-Encoding: chunked
Vary: Accept-Encoding

方法 3:使用 curl 命令检测一个网站是否宕机

curl 命令 是一个用于在服务器间通过支持的协议(DICT、FILE、FTP、FTPS、GOPHER、HTTP、HTTPS、IMAP、IMAPS、LDAP、LDAPS、POP3、POP3S、RTMP、RTSP、SCP、SFTP、SMTP、SMTPS、TELNET 和 TFTP)传输数据的工具。这个工具不支持用户交互。curl 也支持使用代理、用户认证、FTP 上传、HTTP POST 请求、SSL 连接、cookie、断点续传、Metalink 等等。curl由 libcurl 库提供所有与传输有关的能力。

# curl -I https://www.magesh.co.in

HTTP/2 200
date: Thu, 14 Nov 2019 19:39:47 GMT
content-type: text/html
set-cookie: __cfduid=db16c3aee6a75c46a504c15131ead3e7f1573760386; expires=Fri, 13-Nov-20 19:39:46 GMT; path=/; domain=.magesh.co.in; HttpOnly
vary: Accept-Encoding
last-modified: Sun, 14 Jun 2015 11:52:38 GMT
x-cache: HIT from Backend
cf-cache-status: DYNAMIC
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
cf-ray: 535b74123ca4dbf3-LHR

如果你只想看 HTTP 状态码而不是返回的全部信息,用下面的 curl 命令:

# curl -I "www.magesh.co.in" 2>&1 | awk '/HTTP\// {print $2}'
 200

如果你想看一个网站是否宕机,用下面的 bash 脚本:

# vi curl-url-check.sh

#!/bin/bash
if curl -I "https://www.magesh.co.in" 2>&1 | grep -w "200\|301" ; then
    echo "magesh.co.in is up"
else
    echo "magesh.co.in is down"
fi

当你把脚本内容添加到一个文件后,执行文件,查看结果:

# sh curl-url-check.sh

HTTP/2 200
magesh.co.in is up

如果你想看多个网站的状态,使用下面的 shell 脚本:

# vi curl-url-check-1.sh

#!/bin/bash
for site in www.google.com google.co.in www.xyzzz.com
do
if curl -I "$site" 2>&1 | grep -w "200\|301" ; then
    echo "$site is up"
else
    echo "$site is down"
fi
echo "----------------------------------"
done

当你把上面脚本内容添加到一个文件后,执行文件,查看结果:

# sh curl-url-check-1.sh

HTTP/1.1 200 OK
www.google.com is up
----------------------------------
HTTP/1.1 301 Moved Permanently
google.co.in is up
----------------------------------
www.xyzzz.com is down
----------------------------------

方法 4:使用 wget 命令检测一个网站是否宕机

wget 命令(前身是 Geturl)是一个自由开源的命令行下载工具,通过 HTTP、HTTPS、FTP 和其他广泛使用的互联网协议获取文件。wget 是非交互式的命令行工具,由 World Wide Web 和 get 得名。wget 相对于其他工具来说更优秀,功能包括后台运行、递归下载、多文件下载、断点续传、非交互式下载和大文件下载。

# wget -S --spider https://www.magesh.co.in

Spider mode enabled. Check if remote file exists.
--2019-11-15 01:22:00--  https://www.magesh.co.in/
Loaded CA certificate '/etc/ssl/certs/ca-certificates.crt'
Resolving www.magesh.co.in (www.magesh.co.in)… 104.18.35.52, 104.18.34.52, 2606:4700:30::6812:2334, …
Connecting to www.magesh.co.in (www.magesh.co.in)|104.18.35.52|:443… connected.
HTTP request sent, awaiting response…
  HTTP/1.1 200 OK
  Date: Thu, 14 Nov 2019 19:52:01 GMT
  Content-Type: text/html
  Connection: keep-alive
  Set-Cookie: __cfduid=db73306a2f1c72c1318ad4709ef49a3a01573761121; expires=Fri, 13-Nov-20 19:52:01 GMT; path=/; domain=.magesh.co.in; HttpOnly
  Vary: Accept-Encoding
  Last-Modified: Sun, 14 Jun 2015 11:52:38 GMT
  X-Cache: HIT from Backend
  CF-Cache-Status: DYNAMIC
  Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
  Server: cloudflare
  CF-RAY: 535b85fe381ee684-LHR
Length: unspecified [text/html]
Remote file exists and could contain further links,
but recursion is disabled -- not retrieving.

如果你只想看 HTTP 状态码而不是返回的全部结果,用下面的 wget 命令:

# wget --spider -S "www.magesh.co.in" 2>&1 | awk '/HTTP\// {print $2}'
 200

如果你想看一个网站是否宕机,用下面的 bash 脚本:

# vi wget-url-check.sh

#!/bin/bash
if wget --spider -S "https://www.google.com" 2>&1 | grep -w "200\|301" ; then
    echo "Google.com is up"
else
    echo "Google.com is down"
fi

当你把脚本内容添加到一个文件后,执行文件,查看结果:

# wget-url-check.sh

HTTP/1.1 200 OK
Google.com is up

如果你想看多个网站的状态,使用下面的 shell 脚本:

# vi curl-url-check-1.sh

#!/bin/bash
for site in www.google.com google.co.in www.xyzzz.com
do
if wget --spider -S "$site" 2>&1 | grep -w "200\|301" ; then
    echo "$site is up"
else
    echo "$site is down"
fi
echo "----------------------------------"
done

当你把上面脚本内容添加到一个文件后,执行文件,查看结果:

# sh wget-url-check-1.sh

HTTP/1.1 200 OK
www.google.com is up
----------------------------------
HTTP/1.1 301 Moved Permanently
google.co.in is up
----------------------------------
www.xyzzz.com is down
----------------------------------

方法 5:使用 lynx 命令检测一个网站是否宕机

lynx 是一个在 可寻址光标字符单元终端 cursor-addressable character cell terminals 上使用的基于文本的高度可配的 web 浏览器,它是最古老的 web 浏览器并且现在仍在活跃开发。

# lynx -head -dump http://www.magesh.co.in

HTTP/1.1 200 OK
Date: Fri, 15 Nov 2019 08:14:23 GMT
Content-Type: text/html
Connection: close
Set-Cookie: __cfduid=df3cb624024b81df7362f42ede71300951573805662; expires=Sat, 1
4-Nov-20 08:14:22 GMT; path=/; domain=.magesh.co.in; HttpOnly
Vary: Accept-Encoding
Last-Modified: Sun, 14 Jun 2015 11:52:38 GMT
X-Cache: HIT from Backend
CF-Cache-Status: DYNAMIC
Server: cloudflare
CF-RAY: 535fc5704a43e694-LHR

如果你只想看 HTTP 状态码而不是返回的全部结果,用下面的 lynx 命令:

# lynx -head -dump https://www.magesh.co.in 2>&1 | awk '/HTTP\// {print $2}'
 200

如果你想看一个网站是否宕机,用下面的 bash 脚本:

# vi lynx-url-check.sh

#!/bin/bash
if lynx -head -dump http://www.magesh.co.in 2>&1 | grep -w "200\|301" ; then
    echo "magesh.co.in is up"
else
    echo "magesh.co.in is down"
fi

当你把脚本内容添加到一个文件后,执行文件,查看结果:

# sh lynx-url-check.sh

HTTP/1.1 200 OK
magesh.co.in is up

如果你想看多个网站的状态,使用下面的 shell 脚本:

# vi lynx-url-check-1.sh

#!/bin/bash
for site in http://www.google.com https://google.co.in http://www.xyzzz.com
do
if lynx -head -dump "$site" 2>&1 | grep -w "200\|301" ; then
    echo "$site is up"
else
    echo "$site is down"
fi
echo "----------------------------------"
done

当你把上面脚本内容添加到一个文件后,执行文件,查看结果:

# sh lynx-url-check-1.sh

HTTP/1.0 200 OK
http://www.google.com is up
----------------------------------
HTTP/1.0 301 Moved Permanently
https://google.co.in is up
----------------------------------
www.xyzzz.com is down
----------------------------------

方法 6:使用 ping 命令检测一个网站是否宕机

ping 命令(Packet Internet Groper)是网络工具的代表,用于在互联网协议(IP)的网络中测试一个目标主机是否可用/可连接。通过向目标主机发送 ICMP 回应请求报文包并等待 ICMP 回应响应报文来检测主机的可用性。它基于已发送的包、接收到的包和丢失了的包来统计结果数据,通常包含最小/平均/最大响应时间。

# ping -c 5 2daygeek.com

PING 2daygeek.com (104.27.157.177) 56(84) bytes of data.
64 bytes from 104.27.157.177 (104.27.157.177): icmp_seq=1 ttl=58 time=228 ms
64 bytes from 104.27.157.177 (104.27.157.177): icmp_seq=2 ttl=58 time=227 ms
64 bytes from 104.27.157.177 (104.27.157.177): icmp_seq=3 ttl=58 time=250 ms
64 bytes from 104.27.157.177 (104.27.157.177): icmp_seq=4 ttl=58 time=171 ms
64 bytes from 104.27.157.177 (104.27.157.177): icmp_seq=5 ttl=58 time=193 ms

--- 2daygeek.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 13244ms
rtt min/avg/max/mdev = 170.668/213.824/250.295/28.320 ms

附加 1:使用 telnet 命令检测一个网站是否宕机

telnet 命令是一个使用 TELNET 协议用于 TCP/IP 网络中多个主机相互通信的古老的网络协议。它通过 23 端口连接其他设备如计算机和网络设备。telnet 是不安全的协议,现在由于用这个协议发送的数据没有经过加密可能被黑客拦截,所以不推荐使用。大家都使用经过加密且非常安全的 SSH 协议来代替 telnet

# telnet google.com 80

Trying 216.58.194.46…
Connected to google.com.
Escape character is '^]'.
^]
telnet> quit
Connection closed.

附加 2:使用 bash 脚本检测一个网站是否宕机

简而言之,一个 shell 脚本 就是一个包含一系列命令的文件。shell 从文件读取内容按输入顺序逐行在命令行执行。为了让它更有效,我们添加一些条件。这也减轻了 Linux 管理员的负担。

如果你想想用 wget 命令看多个网站的状态,使用下面的 shell 脚本:

# vi wget-url-check-2.sh

#!/bin/bash
for site in www.google.com google.co.in www.xyzzz.com
do
if wget --spider -S "$site" 2>&1 | grep -w "200\|301" > /dev/null ; then
    echo "$site is up"
else
    echo "$site is down"
fi
done

当你把上面脚本内容添加到一个文件后,执行文件,查看结果:

# sh wget-url-check-2.sh

www.google.com is up
google.co.in is up
www.xyzzz.com is down

如果你想用 wget 命令看多个网站的状态,使用下面的 shell 脚本

# vi curl-url-check-2.sh

#!/bin/bash
for site in www.google.com google.co.in www.xyzzz.com
do
if curl -I "$site" 2>&1 | grep -w "200\|301" > /dev/null ; then
    echo "$site is up"
else
    echo "$site is down"
fi
done

当你把上面脚本内容添加到一个文件后,执行文件,查看结果:

# sh curl-url-check-2.sh

www.google.com is up
google.co.in is up
www.xyzzz.com is down

via: https://www.2daygeek.com/linux-command-check-website-is-up-down-alive/

作者:Magesh Maruthamuthu 选题:lujun9972 译者:lxbwolf 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出