分类 技术 下的文章

如果你 双启动 Windows 和 Ubuntu 或任何其他 Linux 发行版,你可能会注意到两个操作系统之间的时间差异。

当你 使用 Linux 时,它会显示正确的时间。但当你进入 Windows 时,它显示的时间是错误的。有时,情况正好相反,Linux 显示的是错误的时间,而 Windows 的时间是正确的。

特别奇怪的是,因为你已连接到互联网,并且已将日期和时间设置为自动使用。

别担心!你并不是唯一一个遇到这种问题的人。你可以在 Linux 终端上使用以下命令来解决这个问题:

timedatectl set-local-rtc 1

同样,不要担心。我会解释为什么你在双启动设置中会遇到时间差。我会向你展示上面的命令是如何修复 Windows 双启动后的时间错误问题的。

为什么 Windows 和 Linux 在双启动时显示不同的时间?

一台电脑有两个主要时钟:系统时钟和硬件时钟。

硬件时钟也叫 RTC(实时时钟)或 CMOS/BIOS 时钟。这个时钟在操作系统之外,在电脑的主板上。即使在你的系统关机后,它也会继续运行。

系统时钟是你在操作系统内看到的。

当计算机开机时,硬件时钟被读取并用于设置系统时钟。之后,系统时钟被用于跟踪时间。如果你的操作系统对系统时钟做了任何改变,比如改变时区等,它就会尝试将这些信息同步到硬件时钟上。

默认情况下,Linux 认为硬件时钟中存储的时间是 UTC,而不是本地时间。另一方面,Windows 认为硬件时钟上存储的时间是本地时间。这就是问题的开始。

让我用例子来解释一下。

你看我在加尔各答 UTC+5:30 时区。安装后,当我把 Ubuntu 中的时区 设置为加尔各答时区时,Ubuntu 会把这个时间信息同步到硬件时钟上,但会有 5:30 的偏移,因为对于 Linux 来说它必须是 UTC。

假设加尔各答时区的当前时间是 15:00,这意味着 UTC 时间是 09:30。

现在当我关闭系统并启动到 Windows 时,硬件时钟有 UTC 时间(本例中为 09:30)。但是 Windows 认为硬件时钟已经存储了本地时间。因此,它改变了系统时钟(应该显示为 15:00),而使用 UTC 时间(09:30)作为本地时间。因此,Windows 显示时间为 09:30,这比实际时间(我们的例子中为 15:00)早了 5:30。

同样,如果我在 Windows 中通过自动时区和时间按钮来设置正确的时间,你知道会发生什么吗?现在它将在系统上显示正确的时间(15:00),并将此信息(注意图片中的“同步你的时钟”选项)同步到硬件时钟。

如果你启动到 Linux,它会从硬件时钟读取时间,而硬件时钟是当地时间(15:00),但由于 Linux 认为它是 UTC 时间,所以它在系统时钟上增加了 5:30 的偏移。现在 Linux 显示的时间是 20:30,比实际时间超出晚了 5:30。

现在你了解了双启动中时差问题的根本原因,是时候看看如何解决这个问题了。

修复 Windows 在 Linux 双启动设置中显示错误时间的问题

有两种方法可以处理这个问题:

  • 让 Windows 将硬件时钟作为 UTC 时间
  • 让 Linux 将硬件时钟作为本地时间

在 Linux 中进行修改是比较容易的,因此我推荐使用第二种方法。

现在 Ubuntu 和大多数其他 Linux 发行版都使用 systemd,因此你可以使用 timedatectl 命令来更改设置。

你要做的是告诉你的 Linux 系统将硬件时钟(RTC)作为本地时间。你可以通过 set-local-rtc (为 RTC 设置本地时间)选项来实现:

timedatectl set-local-rtc 1

如下图所示,RTC 现在使用本地时间。

现在如果你启动 Windows,它把硬件时钟当作本地时间,而这个时间实际上是正确的。当你在 Linux 中启动时,你的 Linux 系统知道硬件时钟使用的是本地时间,而不是 UTC。因此,它不会尝试添加这个时间的偏移。

这就解决了 Linux 和 Windows 双启动时的时差问题。

你会看到一个关于 RTC 不使用本地时间的警告。对于桌面设置,它不应该引起任何问题。至少,我想不出有什么问题。

希望我把事情给你讲清楚了。如果你还有问题,请在下面留言。


via: https://itsfoss.com/wrong-time-dual-boot/

作者:Abhishek Prakash 选题:lujun9972 译者:geekpi 校对:wxy

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

很多时候我与 Markdown 打交道的方式是,先写完一个文件,然后把它转换成 HTML 或其他格式。也有些时候,需要创建一些新的文件。当我要写多个 Markdown 文件时,通常要把他们全部写完之后才转换它们。

我用 pandoc 来转换文件,它可以一次性地转换所有 Markdown 文件。

Markdown 格式的文件可以转换成 .html 文件,有时候我需要把它转换成其他格式,如 epub,这个时候 pandoc 就派上了用场。我更喜欢用命令行,因此本文我会首先介绍它,然而你还可以使用 VSCodium 在非命令行下完成转换。后面我也会介绍它。

使用 pandoc 把多个 Markdown 文件转换成其他格式(命令行方式)

你可以在 Ubuntu 及其他 Debian 系发行版本终端输入下面的命令来快速开始:

sudo apt-get install pandoc

本例中,在名为 md_test 目录下我有四个 Markdown 文件需要转换。

[email protected]:~/Documents/md_test$ ls -l *.md
-rw-r--r-- 1 bdyer bdyer 3374 Apr  7  2020 file01.md
-rw-r--r-- 1 bdyer bdyer  782 Apr  2 05:23 file02.md
-rw-r--r-- 1 bdyer bdyer 9257 Apr  2 05:21 file03.md
-rw-r--r-- 1 bdyer bdyer 9442 Apr  2 05:21 file04.md
[email protected]:~/Documents/md_test$

现在还没有 HTML 文件。现在我要对这些文件使用 pandoc。我会运行一行命令来实现:

  • 调用 pandoc
  • 读取 .md 文件并导出为 .html

下面是我要运行的命令:

for i in *.md ; do echo "$i" && pandoc -s $i -o $i.html ; done

如果你不太理解上面的命令中的 ;,可以参考 在 Linux 中一次执行多个命令

我执行命令后,运行结果如下:

[email protected]:~/Documents/md_test$ for i in *.md ; do echo "$i" && pandoc -s $i -o $i.html ; done
file01.md
file02.md
file03.md
file04.md
[email protected]:~/Documents/md_test$

让我再使用一次 ls 命令来看看是否已经生成了 HTML 文件:

[email protected]:~/Documents/md_test$ ls -l *.html
-rw-r--r-- 1 bdyer bdyer  4291 Apr  2 06:08 file01.md.html
-rw-r--r-- 1 bdyer bdyer  1781 Apr  2 06:08 file02.md.html
-rw-r--r-- 1 bdyer bdyer 10272 Apr  2 06:08 file03.md.html
-rw-r--r-- 1 bdyer bdyer 10502 Apr  2 06:08 file04.md.html
[email protected]:~/Documents/md_test$

转换很成功,现在你已经有了四个 HTML 文件,它们可以用在 Web 服务器上。

pandoc 功能相当多,你可以通过指定输出文件的扩展名来把 Markdown 文件转换成其他支持的格式。不难理解它为什么会被认为是最好的写作开源工具

使用 VSCodium 把 Markdown 文件转换成 HTML(GUI 方式)

就像我们前面说的那样,我通常使用命令行,但是对于批量转换,我不会使用命令行,你也不必。VSCode 或 VSCodium 可以完成批量操作。你只需要安装一个 Markdown-All-in-One 扩展,就可以在一次运行中转换多个 Markdown 文件。

有两种方式安装这个扩展:

  • VSCodium 的终端
  • VSCodium 的插件管理器

通过 VSCodium 的终端安装该扩展:

  1. 点击菜单栏的 终端。会打开终端面板
  2. 输入,或复制下面的命令并粘贴到终端
codium --install-extension yzhang.markdown-all-in-one

注意:如果你使用的 VSCode 而不是 VSCodium,那么请把上面命令中的 codium 替换为 code

第二种安装方式是通过 VSCodium 的插件/扩展管理器:

  1. 点击 VSCodium 窗口左侧的块区域。会出现一个扩展列表,列表最上面有一个搜索框。
  2. 在搜索框中输入 “Markdown All in One”。在列表最上面会出现该扩展。点击 “安装” 按钮来安装它。如果你已经安装过,在安装按钮的位置会出现一个齿轮图标。

安装完成后,你可以打开含有需要转换的 Markdown 文件的文件夹。

点击 VSCodium 窗口左侧的纸张图标。你可以选择文件夹。打开文件夹后,你需要打开至少一个文件。你也可以打开多个文件,但是最少打开一个。

当打开文件后,按下 CTRL+SHIFT+P 唤起命令面板。然后,在出现的搜索框中输入 Markdown。当你输入时,会出现一列 Markdown 相关的命令。其中有一个是 Markdown All in One: Print documents to HTML 命令。点击它:

你需要选择一个文件夹来存放这些文件。它会自动创建一个 out 目录,转换后的 HTML 文件会存放在 out 目录下。从下面的图中可以看到,Markdown 文档被转换成了 HTML 文件。在这里,你可以打开、查看、编辑这些 HTML 文件。

在等待转换 Markdown 文件时,你可以更多地集中精力在写作上。当你准备好时,你就可以把它们转换成 HTML —— 你可以通过两种方式转换它们。


via: https://itsfoss.com/convert-markdown-files/

作者:Bill Dyer 选题:lujun9972 译者:lxbwolf 校对:wxy

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

与其手动执行重复性的任务,不如让 Linux 为你做。

 title=

在 2021 年,人们有更多的理由喜欢 Linux。在这个系列中,我将分享使用 Linux 的 21 个不同理由。自动化是使用 Linux 的最佳理由之一。

我最喜欢 Linux 的一个原因是它愿意为我做工作。我不想执行重复性的任务,这些任务会占用我的时间,或者容易出错,或者我可能会忘记,我安排 Linux 为我做这些工作。

为自动化做准备

“自动化”这个词既让人望而生畏,又让人心动。我发现用模块化的方式来处理它是有帮助的。

1、你想实现什么?

首先,要知道你想产生什么结果。你是要给图片加水印吗?从杂乱的目录中删除文件?执行重要数据的备份?为自己明确定义任务,这样你就知道自己的目标是什么。如果有什么任务是你发现自己每天都在做的,甚至一天一次以上,那么它可能是自动化的候选者。

2、学习你需要的应用

将大的任务分解成小的组件,并学习如何手动但以可重复和可预测的方式产生每个结果。在 Linux 上可以做的很多事情都可以用脚本来完成,但重要的是要认识到你当前的局限性。学习如何自动调整几张图片的大小,以便可以方便地通过电子邮件发送,与使用机器学习为你的每周通讯生成精心制作的艺术品之间有天壤之别。有的事你可以在一个下午学会,而另一件事可能要花上几年时间。然而,我们都必须从某个地方开始,所以只要从小做起,并时刻注意改进的方法。

3、自动化

在 Linux 上使用一个自动化工具来定期实现它。这就是本文介绍的步骤!

要想自动化一些东西,你需要一个脚本来自动化一个任务。在测试时,最好保持简单,所以本文自动化的任务是在 /tmp 目录下创建一个名为 hello 的文件。

#!/bin/sh

touch /tmp/hello

将这个简单的脚本复制并粘贴到一个文本文件中,并将其命名为 example

Cron

每个安装好的 Linux 系统都会有的内置自动化解决方案就是 cron 系统。Linux 用户往往把 cron 笼统地称为你用来安排任务的方法(通常称为 “cron 作业”),但有多个应用程序可以提供 cron 的功能。最通用的是 cronie;它的优点是,它不会像历史上为系统管理员设计的 cron 应用程序那样,假设你的计算机总是开着。

验证你的 Linux 发行版提供的是哪个 cron 系统。如果不是 cronie,你可以从发行版的软件仓库中安装 cronie。如果你的发行版没有 cronie 的软件包,你可以使用旧的 anacron 软件包来代替。anacron 命令是包含在 cronie 中的,所以不管你是如何获得它的,你都要确保在你的系统上有 anacron 命令,然后再继续。anacron 可能需要管理员 root 权限,这取决于你的设置。

$ which anacron
/usr/sbin/anacron

anacron 的工作是确保你的自动化作业定期执行。为了做到这一点,anacron 会检查找出最后一次运行作业的时间,然后检查你告诉它运行作业的频率。

假设你将 anacron 设置为每五天运行一次脚本。每次你打开电脑或从睡眠中唤醒电脑时,anacron都会扫描其日志以确定是否需要运行作业。如果一个作业在五天或更久之前运行,那么 anacron 就会运行该作业。

Cron 作业

许多 Linux 系统都捆绑了一些维护工作,让 cron 来执行。我喜欢把我的工作与系统工作分开,所以我在我的主目录中创建了一个目录。具体来说,有一个叫做 ~/.local 的隐藏文件夹(“local” 的意思是它是为你的用户账户定制的,而不是为你的“全局”计算机系统定制的),所以我创建了子目录 etc/cron.daily 来作为 cron 在我的系统上的家目录。你还必须创建一个 spool 目录来跟踪上次运行作业的时间。

$ mkdir -p ~/.local/etc/cron.daily ~/.var/spool/anacron

你可以把任何你想定期运行的脚本放到 ~/.local/etc/cron.daily 目录中。现在把 example 脚本复制到目录中,然后 用 chmod 命令使其可执行

$ cp example ~/.local/etc/cron.daily
# chmod +x ~/.local/etc/cron.daily/example

接下来,设置 anacron 来运行位于 ~/.local/etc/cron.daily 目录下的任何脚本。

anacron

默认情况下,cron 系统的大部分内容都被认为是系统管理员的领域,因为它通常用于重要的底层任务,如轮换日志文件和更新证书。本文演示的配置是为普通用户设置个人自动化任务而设计的。

要配置 anacron 来运行你的 cron 作业,请在 /.local/etc/anacrontab 创建一个配置文件:

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
1  0  cron.mine    run-parts /home/tux/.local/etc/cron.daily/

这个文件告诉 anacron 每到新的一天(也就是每日),延迟 0 分钟后,就运行(run-parts)所有在 ~/.local/etc/cron.daily 中找到的可执行脚本。有时,会使用几分钟的延迟,这样你的计算机就不会在你登录后就被所有可能的任务冲击。不过这个设置适合测试。

cron.mine 值是进程的一个任意名称。我称它为 cron.mine,但你也可以称它为 cron.personalpenguin 或任何你想要的名字。

验证你的 anacrontab 文件的语法:

$ anacron -T -t ~/.local/etc/anacrontab \
  -S /home/tux/.var/spool/anacron

沉默意味着成功。

在 .profile 中添加 anacron

最后,你必须确保 anacron 以你的本地配置运行。因为你是以普通用户而不是 root 用户的身份运行 anacron,所以你必须将它引导到你的本地配置:告诉 anacron 要做什么的 anacrontab 文件,以及帮助 anacron 跟踪每一个作业最后一次执行是多少天的 spool 目录:

anacron -fn -t /home/tux/.local/etc/anacrontab \
  -S /home/tux/.var/spool/anacron

-fn 选项告诉 anacron 忽略 时间戳,这意味着你强迫它无论如何都要运行你的 cron 作业。这完全是为了测试的目的。

测试你的 cron 作业

现在一切都设置好了,你可以测试作业了。从技术上讲,你可以在不重启的情况下进行测试,但重启是最有意义的,因为这就是设计用来处理中断和不规则的登录会话的。花点时间重启电脑、登录,然后寻找测试文件:

$ ls /tmp/hello
/tmp/hello

假设文件存在,那么你的示例脚本已经成功执行。现在你可以从 ~/.profile 中删除测试选项,留下这个作为你的最终配置。

anacron -t /home/tux/.local/etc/anacrontab \
  -S /home/tux/.var/spool/anacron

使用 anacron

你已经配置好了你的个人自动化基础设施,所以你可以把任何你想让你的计算机替你管理的脚本放到 ~/.local/etc/cron.daily 目录下,它就会按计划运行。

这取决于你希望作业运行的频率。示例脚本是每天执行一次。很明显,这取决于你的计算机在任何一天是否开机和醒着。如果你在周五使用电脑,但把它设置在周末,脚本就不会在周六和周日运行。然而,在周一,脚本会执行,因为 anacron 会知道至少有一天已经过去了。你可以在 ~/.local/etc 中添加每周、每两周、甚至每月的目录,以安排各种各样的间隔。

要添加一个新的时间间隔:

  1. ~/.local/etc 中添加一个目录(例如 cron.weekly)。
  2. ~/.local/etc/anacrontab 中添加一行,以便在新目录下运行脚本。对于每周一次的间隔,其配置如下。7 0 cron.mine run-parts /home/tux/.local/etc/cron.weekly/0 的值可以选择一些分钟数,以适当地延迟脚本的启动)。
  3. 把你的脚本放在 cron.weekly 目录下。

欢迎来到自动化的生活方式。它不会让人感觉到,但你将会变得更有效率。


via: https://opensource.com/article/21/2/linux-automation

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

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

了解 Lua 如何处理数据的读写。

 title=

有些数据是临时的,存储在 RAM 中,只有在应用运行时才有意义。但有些数据是要持久的,存储在硬盘上供以后使用。当你编程时,无论是简单的脚本还是复杂的工具套件,通常都需要读取和写入文件。有时文件可能包含配置选项,而另一些时候这个文件是你的用户用你的应用创建的数据。每种语言都会以不同的方式处理这项任务,本文将演示如何使用 Lua 处理文件数据。

安装 Lua

如果你使用的是 Linux,你可以从你的发行版软件库中安装 Lua。在 macOS 上,你可以从 MacPortsHomebrew 安装 Lua。在 Windows 上,你可以从 Chocolatey 安装 Lua。

安装 Lua 后,打开你最喜欢的文本编辑器并准备开始。

用 Lua 读取文件

Lua 使用 io 库进行数据输入和输出。下面的例子创建了一个名为 ingest 的函数来从文件中读取数据,然后用 :read 函数进行解析。在 Lua 中打开一个文件时,有几种模式可以启用。因为我只需要从这个文件中读取数据,所以我使用 r(代表“读”)模式:

function ingest(file)
   local f = io.open(file, "r")
   local lines = f:read("*all")
   f:close()
   return(lines)
end

myfile=ingest("example.txt")
print(myfile)

在这段代码中,注意到变量 myfile 是为了触发 ingest 函数而创建的,因此,它接收该函数返回的任何内容。ingest 函数返回文件的行数(从一个称为 lines 的变量中0。当最后一步打印 myfile 变量的内容时,文件的行数就会出现在终端中。

如果文件 example.txt 中包含了配置选项,那么我会写一些额外的代码来解析这些数据,可能会使用另一个 Lua 库,这取决于配置是以 INI 文件还是 YAML 文件或其他格式存储。如果数据是 SVG 图形,我会写额外的代码来解析 XML,可能会使用 Lua 的 SVG 库。换句话说,你的代码读取的数据一旦加载到内存中,就可以进行操作,但是它们都需要加载 io 库。

用 Lua 将数据写入文件

无论你是要存储用户用你的应用创建的数据,还是仅仅是关于用户在应用中做了什么的元数据(例如,游戏保存或最近播放的歌曲),都有很多很好的理由来存储数据供以后使用。在 Lua 中,这是通过 io 库实现的,打开一个文件,将数据写入其中,然后关闭文件:

function exgest(file)
   local f = io.open(file, "a")
   io.output(f)
   io.write("hello world\n")
   io.close(f)
end

exgest("example.txt")

为了从文件中读取数据,我以 r 模式打开文件,但这次我使用 a (用于”追加“)将数据写到文件的末尾。因为我是将纯文本写入文件,所以我添加了自己的换行符(/n)。通常情况下,你并不是将原始文本写入文件,你可能会使用一个额外的库来代替写入一个特定的格式。例如,你可能会使用 INI 或 YAML 库来帮助编写配置文件,使用 XML 库来编写 XML,等等。

文件模式

在 Lua 中打开文件时,有一些保护措施和参数来定义如何处理文件。默认值是 r,允许你只读数据:

  • r 只读
  • w 如果文件不存在,覆盖或创建一个新文件。
  • r+ 读取和覆盖。
  • a 追加数据到文件中,或在文件不存在的情况下创建一个新文件。
  • a+ 读取数据,将数据追加到文件中,或文件不存在的话,创建一个新文件。

还有一些其他的(例如,b 代表二进制格式),但这些是最常见的。关于完整的文档,请参考 Lua.org/manual 上的优秀 Lua 文档。

Lua 和文件

和其他编程语言一样,Lua 有大量的库支持来访问文件系统来读写数据。因为 Lua 有一个一致且简单语法,所以很容易对任何格式的文件数据进行复杂的处理。试着在你的下一个软件项目中使用 Lua,或者作为 C 或 C++ 项目的 API。


via: https://opensource.com/article/21/3/lua-files

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

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

昨天我 在 Twitter 上询问大家用 strace 解决了什么问题?,和往常一样,大家真的是给出了自己的答案! 我收到了大约 200 个答案,然后花了很多时间手动将它们归为 9 类。

这些解决的问题都是关于寻找程序依赖的文件、找出程序卡住或慢的原因、或者找出程序失败的原因。这些总体上与我自己使用 strace 的内容相吻合,但也有一些我没有想到的东西!

我不打算在这篇文章里解释什么是 strace,但我有一本 关于它的免费杂志一个讲座 以及 很多博文

问题 1:配置文件在哪里?

最受欢迎的问题是“这个程序有一个配置文件,但我不知道它在哪里”。这可能也是我最常使用 strace 解决的问题,因为这是个很简单的问题。

这很好,因为一个程序有一百万种方法来记录它的配置文件在哪里(在手册页、网站上、--help等),但只有一种方法可以让它真正打开它(用系统调用!)。

问题 2:这个程序还依赖什么文件?

你也可以使用 strace 来查找程序依赖的其他类型的文件,比如:

问题 3:为什么这个程序会挂掉?

你有一个程序,它只是坐在那里什么都不做,这是怎么回事?这个问题特别容易回答,因为很多时候你只需要运行 strace -p PID,看看当前运行的是什么系统调用。你甚至不需要看几百行的输出。

答案通常是“正在等待某种 I/O”。“为什么会卡住”的一些可能的答案(虽然还有很多!):

  • 它一直在轮询 select()
  • 正在 wait() 等待一个子进程完成
  • 它在向某个没有响应的东西发出网络请求
  • 正在进行 write(),但由于缓冲区已满而被阻止。
  • 它在 stdin 上做 read(),等待输入。

有人还举了一个很好的例子,用 strace 调试一个卡住的 df 命令:“用 strace df -h 你可以找到卡住的挂载,然后卸载它”。

问题 4:这个程序卡住了吗?

这是上一个问题的变种:有时一个程序运行的时间比你预期的要长,你只是想知道它是否卡住了,或者它是否还在继续进行。

只要程序在运行过程中进行系统调用,用 strace 就可以超简单地回答这个问题:只需 strace 它,看看它是否在进行新的系统调用!

问题 5:为什么这个程序很慢?

你可以使用 strace 作为一种粗略的剖析工具:strace -t 会显示每次系统调用的时间戳,这样你就可以寻找大的漏洞,找到罪魁祸首。

以下是 Twitter 上 9 个人使用 strace 调试“为什么这个程序很慢?”的小故事。

  • 早在 2000 年,我帮助支持的一个基于 Java 的网站在适度的负载下奄奄一息:页面加载缓慢,甚至完全加载不出来。我们对 J2EE 应用服务器进行了测试,发现它每次只读取一个类文件。开发人员没有使用 BufferedReader,这是典型的 Java 错误。
  • 优化应用程序的启动时间……运行 strace 可以让人大开眼界,因为有大量不必要的文件系统交互在进行(例如,在同一个配置文件上反复打开/读取/关闭;在一个缓慢的 NFS 挂载上加载大量的字体文件,等等)。
  • 问自己为什么在 PHP 中从会话文件中读取(通常是小于 100 字节)非常慢。结果发现一些 flock 系统调用花了大约 60 秒。
  • 一个程序表现得异常缓慢。使用 strace 找出它在每次请求时,通过从 /dev/random 读取数据并耗尽熵来重新初始化其内部伪随机数发生器。
  • 我记得最近一件事是连接到一个任务处理程序,看到它有多少网络调用(这是意想不到的)。
  • strace 显示它打开/读取同一个配置文件数千次。
  • 服务器随机使用 100% 的 CPU 时间,实际流量很低。原来是碰到打开文件数限制,接受一个套接字时,得到 EMFILE 错误而没有报告,然后一直重试。
  • 一个工作流运行超慢,但是没有日志,结果它做一个 POST 请求花了 30 秒而超时,然后重试了 5 次……结果后台服务不堪重负,但是也没有可视性。
  • 使用 strace 注意到 gethostbyname() 需要很长时间才能返回(你不能直接看到 gethostbyname,但你可以看到 strace 中的 DNS 数据包)

问题 6:隐藏的权限错误

有时候程序因为一个神秘的原因而失败,但问题只是有一些它没有权限打开的文件。在理想的世界里,程序会报告这些错误(“Error opening file /dev/whatever: permission denied”),当然这个世界并不完美,所以 strace 真的可以帮助解决这个问题!

这其实是我最近使用 strace 做的事情。我使用了一台 AxiDraw 绘图仪,当我试图启动它时,它打印出了一个难以理解的错误信息。我 strace 它,结果发现我的用户没有权限打开 USB 设备。

问题 7:正在使用什么命令行参数?

有时候,一个脚本正在运行另一个程序,你想知道它传递的是什么命令行标志!

几个来自 Twitter 的例子。

  • 找出实际上是用来编译代码的编译器标志
  • 由于命令行太长,命令失败了

问题 8:为什么这个网络连接失败?

基本上,这里的目标是找到网络连接的域名 / IP 地址。你可以通过 DNS 请求来查找域名,或者通过 connect 系统调用来查找 IP。

一般来说,当 tcpdump 因为某些原因不能使用或者只是因为比较熟悉 strace 时,就经常会使用 strace 调试网络问题。

问题 9:为什么这个程序以一种方式运行时成功,以另一种方式运行时失败?

例如:

  • 同样的二进制程序在一台机器上可以运行,在另一台机器上却失败了
  • 可以运行,但被 systemd 单元文件生成时失败
  • 可以运行,但以 su - user /some/script 的方式运行时失败
  • 可以运行,作为 cron 作业运行时失败

能够比较两种情况下的 strace 输出是非常有用的。虽然我在调试“以我的用户身份工作,而在同一台计算机上以不同方式运行时却失败了”时,第一步是“看看我的环境变量”。

我在做什么:慢慢地建立一些挑战

我之所以会想到这个问题,是因为我一直在慢慢地进行一些挑战,以帮助人们练习使用 strace 和其他命令行工具。我的想法是,给你一个问题,一个终端,你可以自由地以任何方式解决它。

所以我的目标是用它来建立一些你可以用 strace 解决的练习题,这些练习题反映了人们在现实生活中实际使用它解决的问题。

就是这样!

可能还有更多的问题可以用 strace 解决,我在这里还没有讲到,我很乐意听到我错过了什么!

我真的很喜欢看到很多相同的用法一次又一次地出现:至少有 20 个不同的人回答说他们使用 strace 来查找配置文件。而且和以往一样,我觉得这样一个简单的工具(“跟踪系统调用!”)可以用来解决这么多不同类型的问题,真的很令人高兴。


via: https://jvns.ca/blog/2021/04/03/what-problems-do-people-solve-with-strace/

作者:Julia Evans 选题:lujun9972 译者:wxy 校对:wxy

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

如果你知道如何在 C++ 中使用输入输出(I/O)流,那么(原则上)你便能够处理任何类型的输入输出设备。

 title=

在 C++ 中,对文件的读写可以通过使用输入输出流与流运算符 >><< 来进行。当读写文件的时候,这些运算符被应用于代表硬盘驱动器上文件类的实例上。这种基于流的方法有个巨大的优势:从 C++ 的角度,无论你要读取或写入的内容是文件、数据库、控制台,亦或是你通过网络连接的另外一台电脑,这都无关紧要。因此,知道如何使用流运算符来写入文件能够被转用到其他领域。

输入输出流类

C++ 标准库提供了 ios\_base 类。该类作为所有 I/O 流的基类,例如 basic\_ofstreambasic\_ifstream。本例将使用读/写字符的专用类型 ifstreamofstream

  • ofstream:输出文件流,并且其能通过插入运算符 << 来实现。
  • ifstream:输入文件流,并且其能通过提取运算符 >> 来实现。

该两种类型都是在头文件 <fstream> 中所定义。

ios_base 继承的类在写入时可被视为数据接收器,在从其读取时可被视为数据源,与数据本身完全分离。这种面向对象的方法使 关注点分离 separation of concerns 依赖注入 dependency injection 等概念易于实现。

一个简单的例子

本例程是非常简单:实例化了一个 ofstream 来写入,和实例化一个 ifstream 来读取。

#include <iostream> // cout, cin, cerr etc...
#include <fstream> // ifstream, ofstream
#include <string>


int main()
{
    std::string sFilename = "MyFile.txt";    

    /******************************************
     *                                        *
     *                WRITING                 *
     *                                        *
     ******************************************/

    std::ofstream fileSink(sFilename); // Creates an output file stream

    if (!fileSink) {
        std::cerr << "Canot open " << sFilename << std::endl;
        exit(-1);
    }

    /* std::endl will automatically append the correct EOL */
    fileSink << "Hello Open Source World!" << std::endl;


    /******************************************
     *                                        *
     *                READING                 *
     *                                        *
     ******************************************/
   
    std::ifstream fileSource(sFilename); // Creates an input file stream

    if (!fileSource) {
        std::cerr << "Canot open " << sFilename << std::endl;
        exit(-1);
    }
    else {
        // Intermediate buffer
        std::string buffer;

        // By default, the >> operator reads word by workd (till whitespace)
        while (fileSource >> buffer)
        {
            std::cout << buffer << std::endl;
        }
    }

    exit(0);
}

该代码可以在 GitHub 上查看。当你编译并且执行它时,你应该能获得以下输出:

 title=

这是个简化的、适合初学者的例子。如果你想去使用该代码在你自己的应用中,请注意以下几点:

  • 文件流在程序结束的时候自动关闭。如果你想继续执行,那么应该通过调用 close() 方法手动关闭。
  • 这些文件流类继承自 basic\_ios(在多个层次上),并且重载了 ! 运算符。这使你可以进行简单的检查是否可以访问该流。在 cppreference.com 上,你可以找到该检查何时会(或不会)成功的概述,并且可以进一步实现错误处理。
  • 默认情况下,ifstream 停在空白处并跳过它。要逐行读取直到到达 EOF ,请使用 getline(...) 方法。
  • 为了读写二进制文件,请将 std::ios::binary 标志传递给构造函数:这样可以防止 EOL 字符附加到每一行。

从系统角度进行写入

写入文件时,数据将写入系统的内存写入缓冲区中。当系统收到系统调用 sync 时,此缓冲区的内容将被写入硬盘。这也是你在不告知系统的情况下,不要卸下 U 盘的原因。通常,守护进程会定期调用 sync。为了安全起见,也可以手动调用 sync()

#include <unistd.h> // needs to be included

sync();

总结

在 C++ 中读写文件并不那么复杂。更何况,如果你知道如何处理输入输出流,(原则上)那么你也知道如何处理任何类型的输入输出设备。对于各种输入输出设备的库能让你更容易地使用流运算符。这就是为什么知道输入输出流的流程会对你有所助益的原因。


via: https://opensource.com/article/21/3/ccc-input-output

作者:Stephan Avenwedde 选题:lujun9972 译者:wyxplus 校对:wxy

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