2022年11月

Fedora 38 考虑提供面向手机的版本

虽然 Fedora 37 还没有发布,但是开发人员已经在计划下一个版本。一个新的提案建议提供一个面向移动设备的 Phosh 镜像,用于运行专注于智能手机和平板电脑的 Wayland shell,同时提供一个良好的基于 GNOME 的体验。另外预计也会引入一个带有 KDE Plasma Mobile 的镜像。Fedora 38 预计明年春天发布。

消息来源:Phoronix
老王点评:期待看到 Fedora 运行在手机上。

罗马法院要求 Cloudflare 的 DNS 封锁 BT 网站

罗马法院已经确认,Cloudflare 必须通过其公共的 1.1.1.1 DNS 解析器阻止三个 BT 网站。Cloudflare 并不反对阻止针对其客户网站的请求,但认为干扰其 DNS 解析器是有问题的,因为这些措施不容易在地理上加以限制,将影响封锁该政府管辖范围以外的终端用户。

消息来源:Slashdot
老王点评:DNS 作为互联网流量入口的方向标,屡屡被用来做各种滥用。已经习惯了,不是吗?

15000 个网站被黑帽 SEO 利用

安全专家发现,有 15000 个网站(其中大部分是 WordPress 网站),这些网站被重定向到虚假的问答讨论区。恶意威胁者的目标是产生足够的索引页面,以增加虚假问答网站的权重,从而在搜索引擎中获得更好的排名。

消息来源:Bleeping Computer
老王点评:WordPress 这样的 CMS 系统越流行,其被一网打尽的可能越多,尤其是都采用了某些存在缺陷的插件或主题时。

使用 Lua 配置持久化应用设置。

不是所有的应用都需要配置文件;对很多应用来说,在启动时变得焕然一新对它们更有利。例如,简单的工具就极少需要偏好项和设置在使用过程中保持稳定不变。然而,当你编写一个复杂的应用程序时,如果能让用户设置与应用的交互方式,以及应用与系统交互的方式会很不错。这就是配置文件用来做的事情。本文将讨论一些利用 Lua 进行持久化配置的方法。

选择一种格式

关于配置文件很重要的两点是一致性和可预见性。你不会希望为了保存用户偏好项,将信息转储到文件中,然后再花几天去编码实现“逆向工程”,处理最后出现在文件里的随机信息。

这里用一些常用的 配置文件格式。Lua 有一些库可以处理大多数常用的配置格式;在本文中,我会采用 INI 格式。

安装库

Lua 库的核心仓库是 Luarocks.org。你可以在这个网站搜索库,或者你可以安装并使用 luarocks 终端命令。

Linux 环境中,你可以从发行版的软件仓库中下载它,例如:

$ sudo dnf install luarocks

在 macOS 上,请使用 MacPorts 或者 Homebrew。在 Windows 上,请使用 Chocolatey

luarocks 安装后,你可以使用 search 子命令来搜索一个恰当的库。如果你不知道库的名字,可以通过关键词来搜索这个库,例如 ini、xml或者json,这取决于你想要用这个库做什么。打个比方,你可以搜索inifile`, 这个库被我用来解析 INI 格式的文本文件。

$ luarocks search inifile
Search results:
inifile
 1.0-2 (rockspec) - https://luarocks.org
 1.0-2 (src) - https://luarocks.org
 1.0-1 (rockspec) - https://luarocks.org
 [...]

一个开发者容易犯的错误是在系统上安装了这个库却忘了把它和应用打包。这会给没有安装这个库的用户带来麻烦。为了防止这个问题发生,可以使用 --tree 选项将它安装在项目的本地文件夹中。如果你没有这个项目文件夹,那就先创建这个文件夹再安装库:

$ mkdir demo
$ cd demo
$ luarocks install --tree=local inifile

--tree 选项指示 luarocks 创建一个新文件夹并在其中安装你的库,例如这个例子中的 local 文件夹。 使用这个简单的技巧,你可以将所有你项目要使用的依赖项直接安装到项目文件夹中。

配置代码

首先,在一个名 myconfig.ini 的文件中创建一些 INI 数据。

[example]
name=Tux
species=penguin
enabled=false

[demo]
name=Beastie
species=demon
enabled=false

将这个文件保存到你的主目录下,命名为 myconfig.ini, 不要 存到项目文件夹下。你通常会希望配置文件独立于你的文件存在,这样当用户卸载你的应用时,使用应用时产生的数据可以保存在系统中。有些用户会删除不重要的配置文件,但大多数不会。最终,如果他们要重装这个应用,还会保留着所有的用户偏好项。

配置文件的位置以技术来说并不重要,但每一个操作系统都有存储它们的特定或者默认的路径。在 Linux 中,这个路径由 Freedesktop 规范 指定。它规定配置文件被保存在一个名为 ~/.config 的隐藏文件夹中。为了操作时更加清晰明确,可以在主目录下存储配置文件,以便于使用和寻找。

创建第二个文件,命名为 main.lua,并在你喜欢的文本编辑器中打开它。

首先,你必须告诉 Lua 你将想要使用的附加库放置在哪里。package.path 变量决定了 Lua 到哪里去寻找这些库。你可以从终端中查看 Lua 默认的包地址:

$ Lua
> print(package.path)
./?.lua;/usr/share/lua/5.3/?.lua;/usr/share/lua/5.3/?/init.lua;/usr/lib64/lua/5.3/?.lua;/usr/lib64/lua/5.3/?/init.lua

在你的 Lua 代码中,将你本地库的路径添加到 package.path 中:

package.path = package.path .. ';local/share/lua/5.3/?.lua

使用 Lua 解析 INI 文件

当包的位置确定以后,下一件事就是引入 inifile 库并处理一些操作系统逻辑。即使这是一个很简单的应用,代码也需要从操作系统获取到用户主目录的路径,并建立在必要时将文件系统路径返回给操作系统的通信方式。

package.path = package.path .. ';local/share/lua/5.3/?.lua
inifile = require('inifile')

-- find home directory
home = os.getenv('HOME')

-- detect path separator
-- returns '/' for Linux and Mac
-- and '\' for Windows
d = package.config:sub(1,1)

现在你可使用 inifile 来从配置文件解析数据到 Lua 表中。一旦这些数据被导入进表中,你可以像查询其他的 Lua 表一样查询它。

-- parse the INI file and
-- put values into a table called conf
conf = inifile.parse(home .. d .. 'myconfig.ini')

-- print the data for review
print(conf['example']['name'])
print(conf['example']['species'])
print(conf['example']['enabled'])

在终端中运行代码可以看见结果:

$ lua ./main.lua
Tux
penguin
false

这看起来是正确的。试试在 demo 块中执行同样的操作。

使用 INI 格式存储数据

不是所有用来解析的库都会读写数据(通常被称为 \_编码 和 解码),但是 inifile 会这样做。这意味着你可以使用它对配置文件进行修改。

为了改变配置文件中的值,你可以对被解析的表中的变量进行设置,然后把表重写回配置文件中。

-- set enabled to true
conf['example']['enabled'] = true
conf['demo']['enabled'] = true

-- save the change
inifile.save(home .. d .. 'myconfig.ini', conf)

现在再来看看配置文件:

$ cat ~/myconfig.ini
[example]
name=Tux
species=penguin
enabled=true

[demo]
name=Beastie
species=demon
enabled=true

配置文件

按照用户的设想来存储数据对程序来说是至关重要的。幸运的是,这对工程师来说是一个很常规的任务,大多数工作可能早已被完成了。只要找到一个好用的库完成开放格式下编码和解码,你就能为用户提供一致且持续的体验。

以下是完整的演示代码,可供参考。

package.path = package.path .. ';local/share/lua/5.3/?.lua'
inifile = require('inifile')

-- find home directory
home = os.getenv('HOME')

-- detect path separator
-- returns '/' for Linux and Mac
-- and '\' for Windows
d = package.config:sub(1,1)

-- parse the INI file and
-- put values into a table called conf
conf = inifile.parse(home .. d .. 'myconfig.ini')

-- print the data for review
print(conf['example']['name'])
print(conf['example']['species'])
print(conf['example']['enabled'])

-- enable Tux
conf['example']['enabled'] = true

-- save the change
inifile.save(home .. d .. 'myconfig.ini', conf)

via: https://opensource.com/article/21/6/parsing-config-files-lua

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

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

开源的 PSCP 程序可以轻松地在 Windows 和 Linux 计算机之间传输文件和文件夹。

你是否正在寻找一种将文件从 Windows 计算机快速传输到 Linux 计算机并再次传输回来的方法?开源的 PSCP 程序可以轻松传输文件和文件夹,当然它是开源的。

在 Windows 中设置 PATH

了解如何在 Windows 中设置命令路径可以更轻松地使用 PSCP 等方便的程序。如果你不熟悉该过程,请阅读 如何在 Windows 上设置 PATH

使用 PSCP

PSCP(PuTTY 安全复制协议)是一个命令行工具,用于将文件和文件夹从 Windows 计算机传输到 Linux 计算机。

  • 网站 下载 pscp.exe
  • pscp.exe 移动到 PATH 中的文件夹(例如,如果你按照 Opensource.com 上的 PATH 教程进行操作,则为 Desktop\App)。如果你没有设置 PATH 变量,你也可以将 pscp.exe 移动到保存要传输的文件的文件夹中。
  • 使用 Windows 任务栏中的搜索栏在 Windows 计算机上打开 Powershell(在搜索栏中输入 powershell。)
  • 输入 pscp -version 以确认你的计算机可以找到该命令。

IP 地址

在进行传输之前,你必须知道目标计算机的 IP 地址或完全限定域名。假设它是同一网络上的计算机,并且你没有运行 DNS 服务器来解析计算机名称,你可以在 Linux 机器上使用 ip 命令找到目标 IP 地址:

[linux]$ ip addr show |grep 'inet '
inet 127.0.0.1/8 scope host lo
inet 192.168.1.23/24 brd 10.0.1.255 scope global noprefixroute eth0

在所有情况下,127.0.0.1 都是计算机仅用于与自身通信的环回地址,因此在此示例中,正确的地址是 192.168.1.23。在你的系统上,IP 地址可能不同。如果你不确定哪个是哪个,你可以连续尝试每个,直到找到正确的(然后在某处写下来!)

或者,你可以查看路由器的设置,其中列出了通过 DHCP 分配的所有地址。

防火墙和服务器

pscp 命令使用 OpenSSH 协议,因此你的 Linux 计算机必须运行 OpenSSH 服务器软件,并且防火墙必须允许 SSH 流量。

如果你不确定你的 Linux 机器是否正在运行 SSH,请在 Linux 机器上运行以下命令:

[linux]$ sudo systemctl enable --now sshd

要确保你的防火墙允许 SSH 流量,请运行以下命令:

[linux]$ sudo firewall-cmd --add-servicessh --permanent

有关 Linux 上的防火墙的更多信息,请阅读 使用防火墙使 Linux 更强大

传输文件

在这个例子中,我有一个名为 pscp-test.txt 的文件,我想将它从我的 Windows 计算机上的 C:\Users\paul\Documents 传输到我的目标 Linux 计算机主目录 /home/paul

现在你已经有了 pscp 命令和目标地址,你可以传输测试文件 pscp-test.txt。打开 Powershell 并使用 dir 命令切换到示例文件所在的 Documents 文件夹:

PS> dir %USERPROFILE%\Documents\

现在执行传输:

PS> pscp pscp-test.txt [email protected]:/home/paul
| Password:
End of keyboard-interactive prompts from server
pscp-test.txt | 0 kb | 0.0 kB/s | ETA: 00:00:00 | 100%

这是语法,逐字逐句来:

  • pscp:用于传输文件的命令。
  • pscp-test.txt 是你要从 Windows 传输的文件的名称。
  • [email protected] 是我在 Linux 计算机上的用户名,以及 Linux 计算机的 IP 地址。你必须将其替换为你自己的用户和目的地信息。请注意,pscp 需要目标计算机上的目标路径,而 IP 地址末尾的 :/home/paul 指定我希望将文件复制到我的主文件夹。

对 Linux 计算机进行身份验证后,pscp-test.txt 文件将传输到 Linux 计算机。

验证已传输

在你的 Linux 计算机上,打开终端并使用 ls 命令验证文件 pscp-test.txt 是否出现在你的主目录中。

[linux]$ ls
Documents
Downloads
Music
Pictures
pscp-test.txt

从 Linux 系统复制文件

你不仅限于将文件复制到 Linux 系统。使用 pscp,你还可以将文件从 Linux 复制到 Windows。语法是一样的,只是反过来:

PS> pscp [email protected]:/home/paul/pscp-test.txt %USERPROFILE%\Documents\pscp-win.txt

这是语法:

  • pscp:用于传输文件的命令。
  • [email protected]:/home/paul/pscp-test.txt 是我在 Linux 计算机上的用户名、Linux 计算机的 IP 地址,以及我要复制的文件的路径。
  • %USERPROFILE%\Documents 是我的 Windows 计算机上我要保存文件的位置。 请注意,在将文件复制回我的 Windows 计算机时,我可以给它一个新名称,例如 pscp-win.txt,以区别于原始文件。 当然,你不必重命名文件,但对于本演示来说,它是一个有用的快捷方式。

打开文件管理器以验证 pscp-win.txt 文件是否已从 Linux 计算机复制到 Windows C:\Users\paul\Documents 下。

Image of a file manager.

远程复制

借助开源 pscp 命令的强大功能,你可以访问家中的任何计算机、拥有帐户的服务器,甚至是移动设备和 边缘设备


via: https://opensource.com/article/22/10/transfer-files-windows-linux-pscp

作者:Paul 选题:lkxed 译者:geekpi 校对:wxy

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

微软为 Linux 内核提供了套娃支持

微软提交了一个一百多行的补丁,使 Linux 内核可以在嵌套的微软虚拟化管理程序(MSHV)下运行,即可以在 Hyper-V 虚拟机中运行 Hyper-V 虚拟机。

消息来源:Phoronix
老王点评:你真的需要在套娃运行 Linux 吗?你可以试试。

能打败顶尖的围棋 AI 却会输给业余选手

自从 AlphaGo 使用神经网络而通过自我对弈精通围棋后,人类就一败涂地了。研究人员创建了一个对抗性的围棋程序,使用一些超乎常规的下法训练,它在与业余棋手的对弈中败北,但是却可以打败一个顶尖的开源围棋 AI KataGo。KataGo 使用数百万次自我对弈学习围棋,但这仍然不足以覆盖所有可能的情况,留下了可利用的漏洞。研究显示,达到人类水平的 AI 往往会犯一些非常奇怪的错误,以让人类感到惊讶的方式失败。

消息来源:Ars Technica
老王点评:不按套路出牌,连 AI 都受不了。

Linux 内核中出现一个丑陋的“黑科技”

安全研究人员在 Linux 主线内核中发现了一个已经存在三年的“黑科技”:Linux 内核会识别以 “X” 字母开始的进程,并返回“不支持原子模式设置”的错误。这个丑陋的“黑科技”是为了解决旧版本的 X.Org 服务器中的一个错误。但由于没有人愿意再维护 X11,于是这个补丁的提交者觉得,与其修复有问题的代码,不如调整内核以绕开。但事实上这只是检查第一个字母是否是 “X”,扩大了打击面,因为不是所有以 “X” 开头的进程都是 X.Org 的进程。

消息来源:Phoronix
老王点评:这样丑陋的代码显然会被 Linus 破口大骂的,不知道怎么悄悄潜入到内核当中的。

awk 和 Groovy 相辅相成,可以创建强大、有用的脚本。

最近我写了一个使用 Groovy 脚本来清理我的音乐文件中的标签的系列。我开发了一个 框架,可以识别我的音乐目录的结构,并使用它来遍历音乐文件。在该系列的最后一篇文章中,我从框架中分离出一个实用类,我的脚本可以用它来处理文件。

这个独立的框架让我想起了很多 awk 的工作方式。对于那些不熟悉 awk 的人来说,你学习下这本电子书:

《awk 实用指南》

我从 1984 年开始大量使用 awk,当时我们的小公司买了第一台“真正的”计算机,它运行的是 System V Unix。对我来说,awk 是非常完美的:它有 关联内存 associative memory ——将数组视为由字符串而不是数字来索引的。它内置了正则表达式,似乎专为处理数据而生,尤其是在处理数据列时,而且结构紧凑,易于学习。最后,它非常适合在 Unix 工作流使用,从标准输入或文件中读取数据并写入到输出,数据不需要经过其他的转换就出现在了输入流中。

说 awk 是我日常计算工具箱中的一个重要部分一点也不为过。然而,在我使用 awk 的过程中,有几件事让我感到不满意。

可能主要的问题是 awk 善于处理以分隔字段呈现的数据,但很奇怪它不善于处理 CSV 文件,因为 CSV 文件的字段被引号包围时可以嵌入逗号分隔符。另外,自 awk 发明以来,正则表达式已经有了很大的发展,我们需要记住两套正则表达式的语法规则,而这并不利于编写无 bug 的代码。一套这样的规则已经很糟糕了

由于 awk 是一门简洁的语言,因此它缺少很多我认为有用的东西,比如更丰富的基础类型、结构体、switch 语句等等。

相比之下,Groovy 拥有这些能力:可以使用 OpenCSV 库,它很擅长处理 CSV 文件、Java 正则表达式和强大的匹配运算符、丰富的基础类型、类、switch 语句等等。

Groovy 所缺乏的是简单的面向管道的概念,即把要处理数据作为一个传入的流,以及把处理过的数据作为一个传出的流。

但我的音乐目录处理框架让我想到,也许我可以创建一个 Groovy 版本的 awk “引擎”。这就是我写这篇文章的目的。

安装 Java 和 Groovy

Groovy 是基于 Java 的,需要先安装 Java。最新的、合适的 Java 和 Groovy 版本可能都在你的 Linux 发行版的软件库中。Groovy 也可以按照 Groovy 主页 上的说明进行安装。对于 Linux 用户来说,一个不错的选择是 SDKMan,它可以用来获得多个版本的 Java、Groovy 和其他许多相关工具。在这篇文章中,我使用的是 SDK 的版本:

  • Java:OpenJDK 11 的 11.0.12 的开源版本
  • Groovy:3.0.8

使用 Groovy 创建 awk

这里的基本想法是将打开一个或多个文件进行处理、将每行分割成字段、以及提供对数据流的访问等复杂情况封装在三个部分:

  • 在处理数据之前
  • 在处理每行数据时
  • 在处理完所有数据之后

我并不打算用 Groovy 来取代 awk。相反,我只是在努力实现我的典型用例,那就是:

  • 使用一个脚本文件而不是在命令行写代码
  • 处理一个或多个输入文件
  • 设置默认的分隔符为 |,并基于这个分隔符分割所有行
  • 使用 OpenCSV 完成分割工作(awk 做不到)

框架类

下面是用 Groovy 类实现的 “awk 引擎”:

@Grab('com.opencsv:opencsv:5.6')
import com.opencsv.CSVReader
public class AwkEngine {
    // With admiration and respect for
    //     Alfred Aho
    //     Peter Weinberger
    //     Brian Kernighan
    // Thank you for the enormous value
    // brought my job by the awk
    // programming language
    Closure onBegin
    Closure onEachLine
    Closure onEnd
    private String fieldSeparator
    private boolean isFirstLineHeader
    private ArrayList<String> fileNameList
    public AwkEngine(args) {
        this.fileNameList = args
        this.fieldSeparator = "|"
        this.isFirstLineHeader = false
    }
    public AwkEngine(args, fieldSeparator) {
        this.fileNameList = args
        this.fieldSeparator = fieldSeparator
        this.isFirstLineHeader = false
    }
    public AwkEngine(args, fieldSeparator, isFirstLineHeader) {
        this.fileNameList = args
        this.fieldSeparator = fieldSeparator
        this.isFirstLineHeader = isFirstLineHeader
    }
    public void go() {
        this.onBegin()
        int recordNumber = 0
        fileNameList.each { fileName ->
            int fileRecordNumber = 0
            new File(fileName).withReader { reader ->
                def csvReader = new CSVReader(reader,
                    this.fieldSeparator.charAt(0))
                if (isFirstLineHeader) {
                    def csvFieldNames = csvReader.readNext() as
                        ArrayList<String>
                    csvReader.each { fieldsByNumber ->
                        def fieldsByName = csvFieldNames.
                            withIndex().
                            collectEntries { name, index ->
                                [name, fieldsByNumber[index]]
                            }
                        this.onEachLine(fieldsByName,
                                recordNumber, fileName,
                                fileRecordNumber)
                        recordNumber++
                        fileRecordNumber++
                    }
                } else {
                    csvReader.each { fieldsByNumber ->
                        this.onEachLine(fieldsByNumber,
                            recordNumber, fileName,
                            fileRecordNumber)
                        recordNumber++
                        fileRecordNumber++
                    }
                }
            }
        }
        this.onEnd()
    }
}

虽然这看起来是相当多的代码,但许多行是因为太长换行了(例如,通常你会合并第 38 行和第 39 行,第 41 行和第 42 行,等等)。让我们逐行看一下。

第 1 行使用 @Grab 注解从 Maven Central 获取 OpenCSV 库的 5.6 本周。不需要 XML。

第 2 行我引入了 OpenCSV 的 CSVReader

第 3 行,像 Java 一样,我声明了一个 public 实用类 AwkEngine

第 11-13 行定义了脚本所使用的 Groovy 闭包实例,作为该类的钩子。像任何 Groovy 类一样,它们“默认是 public”,但 Groovy 将这些字段创建为 private,并对其进行外部引用(使用 Groovy 提供的 getter 和 setter 方法)。我将在下面的示例脚本中进一步解释这个问题。

第 14-16 行声明了 private 字段 —— 字段分隔符,一个指示文件第一行是否为标题的标志,以及一个文件名的列表。

第 17-31 行定义了三个构造函数。第一个接收命令行参数。第二个接收字段的分隔符。第三个接收指示第一行是否为标题的标志。

第 31-67 行定义了引擎本身,即 go() 方法。

第 33 行调用了 onBegin() 闭包(等同于 awk 的 BEGIN {} 语句)。

第 34 行初始化流的 recordNumber(等同于 awk 的 NR 变量)为 0(注意我这里是从 00 而不是 1 开始的)。

第 35-65 行使用 each {} 来循环处理列表中的文件。

第 36 行初始化文件的 fileRecordNumber(等同于 awk 的 FNR 变量)为 0(从 0 而不是 1 开始)。

第 37-64 行获取一个文件对应的 Reader 实例并处理它。

第 38-39 行获取一个 CSVReader 实例。

第 40 行检测第一行是否为标题。

如果第一行是标题,那么在 41-42 行会从第一行获取字段的标题名字列表。

第 43-54 行处理其他的行。

第 44-48 行把字段的值复制到 name:value 的映射中。

第 49-51 行调用 onEachLine() 闭包(等同于 awk 程序 BEGIN {}END {} 之间的部分,不同的是,这里不能输入执行条件),传入的参数是 name:value 映射、处理过的总行数、文件名和该文件处理过的行数。

第 52-53 行是处理过的总行数和该文件处理过的行数的自增。

如果第一行不是标题:

第 56-62 行处理每一行。

第 57-59 调用 onEachLine() 闭包,传入的参数是字段值的数组、处理过的总行数、文件名和该文件处理过的行数。

第 60-61 行是处理过的总行数和该文件处理过的行数的自增。

第 66 行调用 onEnd() 闭包(等同于 awk 的 END {})。

这就是该框架的内容。现在你可以编译它:

$ groovyc AwkEngine.groovy

一点注释:

如果传入的参数不是一个文件,编译就会失败,并出现标准的 Groovy 堆栈跟踪,看起来像这样:

Caught: java.io.FileNotFoundException: not-a-file (No such file or directory)
java.io.FileNotFoundException: not-a-file (No such file or directory)
at AwkEngine$_go_closure1.doCall(AwkEngine.groovy:46)

OpenCSV 可能会返回 String[] 值,不像 Groovy 中的 List 值那样方便(例如,数组没有 each {})。第 41-42 行将标题字段值数组转换为 list,因此第 57 行的 fieldsByNumber 可能也应该转换为 list。

在脚本中使用这个框架

下面是一个使用 AwkEngine 来处理 /etc/group 之类由冒号分隔并没有标题的文件的简单脚本:

def ae = new AwkEngine(args, ':')
int lineCount = 0
ae.onBegin = {
    println “in begin”
}
ae.onEachLine = { fields, recordNumber, fileName, fileRecordNumber ->
    if (lineCount < 10)
        println “fileName $fileName fields $fields”
    lineCount++
}
ae.onEnd = {
    println “in end”
    println “$lineCount line(s) read”
}
ae.go()

第 1 行 调用的有两个参数的构造函数,传入了参数列表,并定义冒号为分隔符。

第 2 行定义一个脚本级的变量 lineCount,用来记录处理过的行数(注意,Groovy 闭包不要求定义在外部的变量为 final)。

第 3-5 行定义 onBegin() 闭包,在标准输出中打印出 “in begin” 字符串。

第 6-10 行定义 onEachLine() 闭包,打印文件名和前 10 行字段,无论是否为前 10 行,处理过的总行数 lineCount 都会自增。

第 11-14 行定义 onEnd() 闭包,打印 “in end” 字符串和处理过的总行数。

第 15 行运行脚本,使用 AwkEngine

像下面一样运行一下脚本:

$ groovy Test1Awk.groovy /etc/group
in begin
fileName /etc/group fields [root, x, 0, ]
fileName /etc/group fields [daemon, x, 1, ]
fileName /etc/group fields [bin, x, 2, ]
fileName /etc/group fields [sys, x, 3, ]
fileName /etc/group fields [adm, x, 4, syslog,clh]
fileName /etc/group fields [tty, x, 5, ]
fileName /etc/group fields [disk, x, 6, ]
fileName /etc/group fields [lp, x, 7, ]
fileName /etc/group fields [mail, x, 8, ]
fileName /etc/group fields [news, x, 9, ]
in end
78 line(s) read
$

当然,编译框架类生成的 .class 文件需要在 classpath 中,这样才能正常运行。通常你可以用 jar 把这些 class 文件打包起来。

我非常喜欢 Groovy 对行为委托的支持,这在其他语言中需要各种诡异的手段。许多年来,Java 需要匿名类和相当多的额外代码。Lambda 已经在很大程度上解决了这个问题,但它们仍然不能引用其范围之外的非 final 变量。

下面是另一个更有趣的脚本,它很容易让人想起我对 awk 的典型使用方式:

def ae = new AwkEngine(args, ';', true)
ae.onBegin = {
    // nothing to do here
}
def regionCount = [:]
    ae.onEachLine = { fields, recordNumber, fileName, fileRecordNumber ->
        regionCount[fields.REGION] =
            (regionCount.containsKey(fields.REGION) ?
                regionCount[fields.REGION] : 0) +
            (fields.PERSONAS as Integer)
}
ae.onEnd = {
    regionCount.each { region, population ->
        println “Region $region population $population”
    }
}
ae.go()

第 1 行调用了三个函数的构造方法,true 表示这是“真正的 CSV” 文件,第一行为标题。由于它是西班牙语的文件,因此它的逗号表示数字的,标准的分隔符是分号。

第 2-4 行定义 onBegin() 闭包,这里什么也不做。

第 5 行定义一个(空的)LinkedHashmap,键是 String 类型,值是 Integer 类型。数据文件来自于智利最近的人口普查,你要在这个脚本中计算出智利每个地区的人口数量。

第 6-11 行处理文件中的行(加上标题一共有 180,500 行)—— 请注意在这个案例中,由于你定义 第 1 行为 CSV 列的标题,因此 fields 参数会成为 LinkedHashMap<String,String> 实例。

第 7-10 行是 regionCount 映射计数增加,键是 REGION 字段的值,值是 PERSONAS 字段的值 —— 请注意,与 awk 不同,在 Groovy 中你不能在赋值操作的右边使用一个不存在的映射而期望得到空值或零值。

第 12-16 行,打印每个地区的人口数量。

第 17 行运行脚本,调用 AwkEngine

像下面一样运行一下脚本:

$ groovy Test2Awk.groovy ~/Downloads/Censo2017/ManzanaEntidad_CSV/Censo*csv
Region 1 population 330558
Region 2 population 607534
Region 3 population 286168
Region 4 population 757586
Region 5 population 1815902
Region 6 population 914555
Region 7 population 1044950
Region 8 population 1556805
Region 16 population 480609
Region 9 population 957224
Region 10 population 828708
Region 11 population 103158
Region 12 population 166533
Region 13 population 7112808
Region 14 population 384837
Region 15 population 226068
$

以上为全部内容。对于那些喜欢 awk 但又希望得到更多的东西的人,我希望你能喜欢这种 Groovy 的方法。


via: https://opensource.com/article/22/9/awk-groovy

作者:Chris Hermansen 选题:lkxed 译者:lxbwolf 校对:wxy

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

打算为你的项目开发工作安装 Python 3.11?下面是如何在 Ubuntu 等发行版中安装 Python 3.11 的方法。

Python 3.11 于 2022 年 10 月 25 日发布,并声称比之前的 Python 3.10 版本快 10% - 60%。

一如既往,3.11 中的功能和改进列表明显较多。下面是一个简介:

  • 错误回溯更明确,可以指出导致错误的确切语句。
  • 引入异常组和新的 except* 语法。
  • 你可以在基础表达式中添加自定义文本,以便在你的代码中更好地处理错误。
  • 引入 Variadic 泛型,允许在 Python 数值库(如 NumPy)中使用类似数组的结构。
  • 字典类型 TypedDict 得到了改进,现在你可以指定个别字典项目是必须的还是可选的。
  • 引入了 Self 注解,允许类返回它们自己的类型实例。

还有很多,你可以在官方的 3.11 亮点页面 上详细了解。

Linux 发行版中的当前 Python 版本

Ubuntu 22.04 LTS 带有 Python 3.10,而最近发布的 Ubuntu 22.10 Kinetic Kudu 也是同样的版本。然而, Kinetick Kudu 可能会在几周内采用 3.11。

另外,Fedora 37 已经有了 Python 3.11 RC2,并将提供该版本。

所以,如果你正在运行 Ubuntu 22.04 LTS、Linux Mint 21 或任何基于 Ubuntu-LTS 的发行版,这里是你如何通过 PPA 安装 Python 3.11 的方法。

注意:谨慎地使用这个方法。确保你知道你在做什么,因为替换 Linux 发行版的基础 Python 版本可能会导致系统不稳定。许多默认的应用程序和软件包都依赖于 3.10 版本。

如何在 Ubuntu 和相关发行版中安装 Python 3.11

打开终端提示,添加以下 PPA:

sudo add-apt-repository ppa:deadsnakes/ppa

使用下面的命令刷新缓存:

sudo apt update 

并使用下面的命令安装 Python 3.11:

sudo apt install python3.11

在 Ubuntu 22.04 LTS 中安装 Python 3.11

设置默认的 Python 版本

理论上,你可以在 Linux 发行版中安装多个版本的 Python,但只能默认一个版本。将 Python 3.11 设置为默认版本需要一些额外的步骤。请跟我做。

然而,在这之前,请确保你知道哪些应用程序依赖于 Python 3.10。你可以使用 apt-cache rdepends 命令轻松地找到它,如下所示:

debugpoint@debugpoint-22-04:~$ apt-cache rdepends python3.10
python3.10
Reverse Depends:
python3.10-dbg
python3.10-venv
python3.10-full
libpython3.10-testsuite
idle-python3.10
idle-python3.10
python3.10-minimal
python3.10-doc
python3.10-dev
python3
[截断]
python3
python3-uno
python3-all
gedit

使用 Python 3.11 作为默认的 Python3

首先,从终端使用以下命令检查当前的默认版本:

python3 --version

使用 update-alternatives 来创建 python3 的符号链接:

sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 2

并通过命令选择哪一个作为 Python3 使用:

sudo update-alternatives --config python3

设置默认的 Python 版本为 3.11

现在你可以开始在你当前的 Ubuntu 版本中使用最新的 Python 来进行工作/学习了。你可以使用上述命令切换到库存版本,并随时改变版本。

如果你使用上述安装方法切换到 3.11,那么请确保你检查所有必要的应用程序,看它们是否工作正常。

最后,如果你遇到问题,请在评论区告诉我。


via: https://www.debugpoint.com/install-python-3-11-ubuntu/

作者:Arindam 选题:lkxed 译者:wxy 校对:wxy

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