Seth Kenlon 发布的文章

许多大型代码库中都有 Lisp 代码的身影,因此,熟悉一下这门语言是一个明智之举。

早在 1958 年,Lisp 就被发明出来了,它是世界上第二古老的计算机编程语言(LCTT 译注:最古老的编程语言是 Fortran,诞生于 1957 年)。它有许多现代的衍生品,包括 Common Lisp、Emacs Lisp(Elisp)、Clojure、Racket、Scheme、Fennel 和 GNU Guile 等。

那些喜欢思考编程语言的设计的人,往往都喜欢 Lisp,因为它的语法和数据有着相同的结构:Lisp 代码实际上是 一个列表的列表 a list of lists ,它的名字其实是 “ 列表处理 LISt Processing ” 的简写。而那些喜欢思考编程语言的美学的人,往往都讨厌 Lisp,因为它经常使用括号来定义范围;事实上,编程界也有一个广为流传的笑话:Lisp 代表的其实是 “大量烦人的多余括号” Lots of Irritating Superfluous Parentheses

不管你是喜欢还是讨厌 Lisp 的设计哲学,你都不得不承认,它都是一门有趣的语言,过去如此,现在亦然(这得归功于现代方言 Clojure 和 Guile)。你可能会惊讶于在任何特定行业的大代码库中潜伏着多少 Lisp 代码,因此,现在开始学习 Lisp,至少熟悉一下它,不失为一个好主意。

安装 Lisp

Lisp 有很多不同的实现。比较流行的开源版本有 SBCLGNU LispGNU Common Lisp(GCL)。你可以使用发行版的包管理器安装它们中的任意一个,在本文中,我是用的是 clisp(LCTT 译注:也就是 GNU Lisp,一种 ANSI Common Lisp 的实现)。

以下是在不同的 Linux 发行版中安装 clisp 的步骤。

在 Fedora Linux 上,使用 dnf

$ sudo dnf install clisp

在 Debian 上,使用 apt

$ sudo apt install clisp

在 macOS 上,使用 MacPorts 或者 Homebrew

# 使用 MacPorts
$ sudo port install clisp

# 使用 Homebrew
$ brew install clisp

在 Windows 上,你可以使用 clisp on Cygwin 或者从 gnu.org/software/gcl 上下载 GCL 的二进制文件。

虽然我使用 clisp 命令来运行 Lisp 代码,但是本文中涉及到的大多数语法规则,对任何 Lisp 实现都是适用的。如果你选择使用一个不同的 Lisp 实现,除了用来运行 Lisp 代码的命令会和我不一样外(比如,你可能要用 gclsbcl 而不是 clisp),其它的所有东西都是相同的。

列表处理

Lisp 源代码的基本单元是 “ 表达式 expression ”,它在形式上是一个列表。举个例子,下面就是一个列表,它由一个操作符(+)和两个整数(12)组成:

(+ 1 2)

同时,它也是一个 Lisp 表达式,内容是一个符号(+,会被解析成一个加法函数)和它的两个参数(12)。你可以在 Common Lisp 的交互式环境(即 REPL)中运行该表达式和其它表达式。如果你熟悉 Python 的 IDLE,那么你应该会对 Lisp 的 REPL 感到亲切。(LCTT 译注:REPL 的全称是 “Read-Eval-Print Loop”,意思是 “‘读取-求值-输出’循环”,这个名字很好地描述了它的工作过程。)

要进入到 REPL 中,只需运行 Common Lisp 即可:

$ clisp
[1]>

在 REPL 提示符中,尝试输入一些表达式:

[1]> (+ 1 2)
3
[2]> (- 1 2)
-1
[3]> (- 2 1)
1
[4]> (+ 2 3 4)
9

函数

在了解了 Lisp 表达式的基本结构后,你可以使用函数来做更多有用的事。譬如,print 函数可以接受任意数量的参数,然后把它们都显示在你的终端上,pprint 函数还可以实现格式化打印。还有更多不同的打印函数,不过,pprint 在 REPL 中的效果就挺好的:

[1]> (pprint "hello world")

"hello world"

[2]>

你可以使用 defun 函数来创建一个自定义函数。defun 函数需要你提供自定义函数的名称,以及它接受的参数列表:

[1]> (defun myprinter (s) (pprint s))
MYPRINTER
[2]> (myprinter "hello world")

"hello world"

[3]>

变量

你可以使用 setf 函数来在 Lisp 中创建变量:

[1]> (setf foo "hello world")
"hello world"
[2]> (pprint foo)

"hello world"

[3]>

你可以在表达式里嵌套表达式(就像使用某种管道一样)。举个例子,你可以先使用 string-upcase 函数,把某个字符串的所有字符转换成大写,然后再使用 pprint 函数,将它的内容格式化打印到终端上:

[3]> (pprint (string-upcase foo))

"HELLO WORLD"

[4]>

Lisp 是动态类型语言,这意味着,你在给变量赋值时不需要声明它的类型。Lisp 默认会把整数当作整数来处理:

[1]> (setf foo 2)
[2]> (setf bar 3)
[3]> (+ foo bar)
5

如果你想让整数被当作字符串来处理,你可以给它加上引号:

[4]> (setf foo "2")
"2"
[5]> (setf bar "3")
"3"
[6]> (+ foo bar)

*** - +: "2" is not a number
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead.
ABORT          :R2      Abort main loop
Break 1 [7]>

在这个示例 REPL 会话中,变量 foobar 都被赋值为加了引号的数字,因此,Lisp 会把它们当作字符串来处理。数学运算符不能够用在字符串上,因此 REPL 进入了调试器模式。想要跳出这个调试器,你需要按下 Ctrl+D 才行(LCTT 译注:就 clisp 而言,使用 quit 关键字也可以退出)。

你可以使用 typep 函数对一些对象进行类型检查,它可以测试对象是否为某个特定数据类型。返回值 TNIL 分别代表 TrueFalse

[4]> (typep foo 'string)
NIL
[5]> (typep foo 'integer)
T

stringinteger 前面加上了一个单引号('),这是为了防止 Lisp(错误地)把这两个单词当作是变量来求值:

[6]> (typep foo string)
*** - SYSTEM::READ-EVAL-PRINT: variable STRING has no value
[...]

这是一种保护某些术语(LCTT 译注:类似于字符串转义)的简便方法,正常情况下它是用 quote 函数来实现的:

[7]> (typep foo (quote string))
NIL
[5]> (typep foo (quote integer))
T

列表

不出人意料,你当然也可以在 Lisp 中创建列表:

[1]> (setf foo (list "hello" "world"))
("hello" "world")

你可以使用 nth 函数来索引列表:

[2]> (nth 0 foo)
"hello"
[3]> (pprint (string-capitalize (nth 1 foo)))

"World"

退出 REPL

要结束一个 REPL 会话,你需要按下键盘上的 Ctrl+D,或者是使用 Lisp 的 quit 关键字:

[99]> (quit)
$

编写脚本

Lisp 可以被编译,也可以作为解释型的脚本语言来使用。在你刚开始学习的时候,后者很可能是最容易的方式,特别是当你已经熟悉 Python 或 Shell 脚本 时。

下面是一个用 Common Lisp 编写的简单的“掷骰子”脚本:

#!/usr/bin/clisp

(defun roller (num)  
  (pprint (random (parse-integer (nth 0 num))))
)

(setf userput *args*)
(setf *random-state* (make-random-state t))
(roller userput)

脚本的第一行注释(LCTT 译注:称之为“ 释伴 shebang ”)告诉了你的 POSIX 终端,该使用什么可执行文件来运行这个脚本。

roller 函数使用 defun 函数创建,它在内部使用 random 函数来打印一个伪随机数,这个伪随机数严格小于 num 列表中下标为 0 的元素。在脚本中,这个 num 列表还没有被创建,不过没关系,因为只有当脚本被调用时,函数才会执行。

接下来的那一行,我们把运行脚本时提供的任意参数,都赋值给一个叫做 userput 的变量。这个 userput 变量是一个列表,当它被传递给 roller 函数后,它就会变成参数 num

脚本的倒数第二行产生了一个“随机种子”。这为 Lisp 提供了足够的随机性来生成一个几乎随机的数字。

最后一行调用了自定义的 roller 函数,并将 userput 列表作为唯一的参数传递给它。

将这个文件保存为 dice.lisp,并赋予它可执行权限:

$ chmod +x dice.lisp

最后,运行它,并给它提供一个数字,以作为它选择随机数的最大值:

$ ./dice.lisp 21

13
$ ./dice.lisp 21

7
$ ./dice.lisp 21

20

看起来还不错!

你或许注意到,你的模拟骰子有可能会是 0,并且永远达不到你提供给它的最大值参数。换句话说,对于一个 20 面的骰子,这个脚本永远投不出 20(除非你把 0 当作 20)。有一个简单的解决办法,它只需要用到在本文中介绍的知识,你能够想到吗?

学习 Lisp

无论你是想将 Lisp 作为个人脚本的实用语言,还是为了助力你的职业生涯,抑或是仅仅作为一个有趣的实验,你都可以去看看一年一度(LCTT 译注:应该是两年一度)的 Lisp 游戏果酱 Game Jam ,从而收获一些特别有创意的用途(其中的大多数提交都是开源的,因此你可以查看代码以从中学习)。

Lisp 是一门有趣而独特的语言,它有着不断增长的开发者用户群、足够悠久的历史和新兴的方言,因此,它有能力让从事各个行业的程序员都满意。


via: https://opensource.com/article/21/5/learn-lisp

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

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

JavaScript 是为 Web 而生的,但它可以做的事远不止于此。本文将带领你了解它的基础知识,然后你可以下载我们的备忘清单,以便随时掌握详细信息。

JavaScript 是一种充满惊喜的编程语言。许多人第一次遇到 JavaScript 时,它通常是作为一种 Web 语言出现的。所有主流浏览器都有一个 JavaScript 引擎;并且,还有一些流行的框架,如 JQuery、Cash 和 Bootstrap 等,它们可以帮助简化网页设计;甚至还有用 JavaScript 编写的编程环境。它似乎在互联网上无处不在,但事实证明,它对于 Electron 等项目来说也是一种有用的语言。Electron 是一个构建跨平台桌面应用程序的开源工具包,它使用的语言就是 JavaScript。

JavaScript 语言的用途多到令人惊讶,它拥有各种各样的库,而不仅仅是用于制作网站。它的基础知识十分容易掌握,因此,它可以作为一个起点,助你跨出构建你想象中的东西的第一步。

安装 JavaScript

随着你的 JavaScript 水平不断提高,你可能会发现自己需要高级的 JavaScript 库和运行时环境。不过,刚开始学习的时候,你是根本不需要安装 JavaScript 环境的。因为所有主流的 Web 浏览器都包含一个 JavaScript 引擎来运行代码。你可以使用自己喜欢的文本编辑器编写 JavaScript,将其加载到 Web 浏览器中,接着你就能看到代码的作用。

上手 JavaScript

要编写你的第一个 JavaScript 代码,请打开你喜欢的文本编辑器,例如 AtomVSCode 等。因为它是为 Web 开发的,所以 JavaScript 可以很好地与 HTML 配合使用。因此,我们先来尝试一些基本的 HTML:

<html>
  <head>
    <title>JS</title>
  </head>
  <body>
    <p id="example">Nothing here.</p>
  </body>
</html>

保存这个文件,然后在 Web 浏览器中打开它。

浏览器中显示的 HTML

要将 JavaScript 添加到这个简单的 HTML 页面,你可以创建一个 JavaScript 文件并在页面的 <head> 中引用它,或者只需使用 <script> 标记将 JavaScript 代码嵌入 HTML 中。在这个例子中,我嵌入了下面的代码:

<html>
  <head>
    <title>JS</title>
  </head>
  <body>
    <p id="example">Nothing here.</p>

    <script>
      let myvariable = "Hello world!";

      document.getElementById("example").innerHTML = myvariable;
    </script>

  </body>
</html>

在浏览器中重新加载页面。

在浏览器中显示带有 JavaScript 的 HTML

如你所见,<p> 标签仍然包含字符串 "Nothing here",但是当它被渲染时,JavaScript 会改变它,使其包含 "Hello world"。是的,JavaScript 具有重建​​(或只是帮助构建)网页的能力。

这个简单脚本中的 JavaScript 做了两件事。首先,它创建一个名为 myvariable 的变量,并将字符串 "Hello world!" 放置其中。然后,它会在当前文档(浏览器呈现的网页)中搜索 ID 为 example 的所有 HTML 元素。当它找到 example 时,它使用了 innerHTML 属性将 HTML 元素的内容替换为 myvariable 的内容。

当然,我们也可以不用自定义变量。因为,使用动态创建的内容来填充 HTML 元素也是容易的。例如,你可以使用当前时间戳来填充它:

<html>
  <head>
    <title>JS</title>
  </head>
  <body>
    <p id="example">Date and time appears here.</p>

    <script>
      document.getElementById("example").innerHTML = Date();
    </script>
    
  </body>
</html>

重新加载页面,你就可以看到在呈现页面时生成的时间戳。再重新加载几次,你可以观察到秒数会不断增加。

JavaScript 语法

在编程中, 语法 syntax 指的是如何编写句子(或“行”)的规则。在 JavaScript 中,每行代码必须以分号(;)结尾,以便运行代码的 JavaScript 引擎知道何时停止阅读。(LCTT 译注:从实用角度看,此处的“必须”其实是不正确的,大多数 JS 引擎都支持不加分号。Vue.js 的作者尤雨溪认为“没有应该不应该,只有你自己喜欢不喜欢”,他同时表示,“Vue.js 的代码全部不带分号”。详情可以查看他在知乎上对于此问题的 回答。)

单词(或 字符串 strings )必须用引号(")括起来,而数字(或 整数 integers )则不用。

几乎所有其他东西都是 JavaScript 语言的约定,例如变量、数组、条件语句、对象、函数等等。

在 JavaScript 中创建变量

变量是数据的容器。你可以将变量视为一个盒子,你在其中放置数据,以便与程序的其他部分共享它。要在 JavaScript 中创建变量,你可以选用关键字 letvar 中的一个,请根据你打算如何使用变量来选择:var 关键字用于创建一个供整个程序使用的变量,而 let 只为特定目的创建变量,通常在函数或循环的内部使用。(LCTT 译注:还有 const 关键字,它用于创建一个常量。)

JavaScript 内置的 typeof 函数可以帮助你识别变量包含的数据的类型。使用第一个示例,你可以修改显示文本,来显示 myvariable 包含的数据的类型:

<string>
let myvariable = "Hello world!";
document.getElementById("example").innerHTML = typeof(myvariable);
</string>

接着,你就会发现 Web 浏览器中显示出 “string” 字样,因为该变量包含的数据是 "Hello world!"。在 myvariable 中存储不同类型的数据(例如整数),浏览器就会把不同的数据类型打印到示例网页上。尝试将 myvariable 的内容更改为你喜欢的数字,然后重新加载页面。

在 JavaScript 中创建函数

编程中的函数是独立的数据处理器。正是它们使编程得以 模块化。因为函数的存在,程序员可以编写通用库,例如​​,调整图像大小或统计时间花费的库,以供其他和你一样的程序员在他们的代码中使用。

要创建一个函数,你可以为函数提供一个自定义名称,后面跟着用大括号括起来的、任意数量的代码。

下面是一个简单的网页,其中包含了一个剪裁过的图像,还有一个分析图像并返回真实图像尺寸的按钮。在这个示例代码中,<button> 这个 HTML 元素使用了 JavaScript 的内置函数 onclick 来检测用户交互,它会触发一个名为 get_size 的自定义函数。具体代码如下:

<html>
  <head>
    <title>Imager</title>
  </head>
  <body>

    <div>
      <button onclick="get_size(document.getElementById('myimg'))">
        Get image size
    </button>
    </div>
    
    <div>
      <img style="width: 15%" id="myimg" src="penguin.png" />
    </div>
   
    <script>
      function get_size(i) {
        let w = i.naturalWidth;
        let h = i.naturalHeight;
        alert(w + " by " + h);
      }
    </script>
    
  </body>
</html>

保存这个文件,并将其加载到 Web 浏览器中以尝试这段代码。

自定义的 get_size 函数返回了图像尺寸

使用 JavaScript 的跨平台应用程序

你可以从代码示例中看到,JavaScript 和 HTML 紧密协作,从而创建了有凝聚力的用户体验。这是 JavaScript 的一大优势。当你使用 JavaScript 编写代码时,你继承了现代计算中最常见的用户界面之一,而它与平台无关,那就是 Web 浏览器。你的代码本质上是跨平台的,因此你的应用程序,无论是简单的图像大小分析器还是复杂的图像编辑器、视频游戏,或者你梦想的任何其他东西,都可以被所有人使用,无论是通过 Web 浏览器,还是桌面(如果你同时提供了一个 Electron 应用)。

学习 JavaScript 既简单又有趣。网络上有很多网站提供了相关教程,还有超过一百万个 JavaScript 库可帮助你与设备、外围设备、物联网、服务器、文件系统等进行交互。在你学习的过程中,请将我们的 JavaScript 备忘单 放在身边,以便记住语法和结构的细节。

JavaScript 备忘单

via: https://opensource.com/article/21/7/javascript-cheat-sheet

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

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

编译软件在你如何运行你的系统方面给你很大的灵活性。LD_LIBRARY_PATH 变量,以及 GCC 的 -L-l 选项,是这种灵活性的组成部分。

编译软件是开发者经常做的事情,在开源世界中,一些用户甚至选择自己动手。Linux 播客 Dann Washko 称源码为“通用包格式”,因为它包含了使一个应用在任何平台上运行所需的所有组件。当然,并不是所有的源码都是为所有的系统编写的,所以它只是在目标系统的子集内是“通用”的,但问题是,源码是非常灵活的。有了开源,你可以决定代码的编译和运行方式。

当你在编译代码时,你通常要处理多个源文件。开发人员倾向于将不同的类或模块放在不同的文件中,这样它们可以被单独维护,甚至可能被不同的项目使用。但当你编译这些文件时,许多文件会被编译成一个可执行文件。

这通常是通过创建共享库来完成的,然后从可执行文件中动态链接回它们。这样可以通过保持模块化功能的外部性来保持可执行文件的小型化,并确保库可以独立于使用它们的应用而被更新。

在编译过程中定位一个共享对象

当你 用 GCC 编译 时,你通常需要在你的工作站上安装一个库,以便 GCC 能够定位到它。默认情况下,GCC 假定库在系统库路径中,例如 /lib64/usr/lib64。然而,如果你要链接到一个你自己的尚未安装的库,或者你需要链接到一个没有安装在标准位置的库,那么你必须帮助 GCC 找到这些文件。

有两个选项对于在 GCC 中寻找库很重要:

  • -L(大写字母 L)在 GCC 的搜索位置上增加一个额外的库路径。
  • -l(小写字母 L)设置你要链接的库的名字。

例如,假设你写了一个叫做 libexample.so 的库,并且你想在编译你的应用 demo.c 时使用它。首先,从 demo.c 创建一个对象文件:

$ gcc -I ./include -c src/demo.c

-I 选项在 GCC 搜索头文件的路径中增加了一个目录。在这个例子中,我假设自定义头文件在一个名为 include 的本地目录中。-c 选项防止 GCC 运行链接器,因为这个任务只是为了创建一个对象文件。结果如下:

$ ls
demo.o   include/   lib/    src/

现在你可以使用 -L 选项为你的库设置一个路径,然后进行编译:

$ gcc -L`pwd`/lib -o myDemo demo.o -lexample

注意,-L 选项在 -l 选项之前。这很重要,因为如果在你告诉 GCC 查找非默认库之前没有将 -L 添加到 GCC 的搜索路径中,GCC 就不知道要在你的自定义位置上搜索。编译成功了,但当你试图运行它时,却出现了问题:

$ ./myDemo
./myDemo: error while loading shared libraries:
libexample.so: cannot open shared object file:
No such file or directory

用 ldd 排除故障

ldd 工具可以打印出共享对象的依赖关系,它在排除类似问题时很有用:

$ ldd ./myDemo
        linux-vdso.so.1 (0x00007ffe151df000)
        libexample.so => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007f514b60a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f514b839000)

你已经知道定位不到 libexample,但 ldd 输出至少确认了它对工作库的期望位置。例如,libc.so.6已经被定位,ldd 显示其完整路径。

LD\_LIBRARY\_PATH

LD_LIBRARY_PATH 环境变量 定义了库的路径。如果你正在运行一个依赖于没有安装到标准目录的库的应用程,你可以使用 LD_LIBRARY_PATH 添加到系统的库搜索路径。

有几种设置环境变量的方法,但最灵活的是在运行命令前放置环境变量。看看设置 LD_LIBRARY_PATHldd 命令在分析一个“损坏”的可执行文件时的作用:

$ LD_LIBRARY_PATH=`pwd`/lib ldd ./
   linux-vdso.so.1 (0x00007ffe515bb000)
   libexample.so => /tmp/Demo/lib/libexample.so (0x0000...
   libc.so.6 => /lib64/libc.so.6 (0x00007eff037ee000)
   /lib64/ld-linux-x86-64.so.2 (0x00007eff03a22000)

这也同样适用于你的自定义命令:

$ LD_LIBRARY_PATH=`pwd`/lib myDemo
hello world!

然而,如果你移动库文件或可执行文件,它又会失效:

$ mv lib/libexample.so ~/.local/lib64
$ LD_LIBRARY_PATH=`pwd`/lib myDemo
./myDemo: error while loading shared libraries...

要修复它,你必须调整 LD_LIBRARY_PATH 以匹配库的新位置:

$ LD_LIBRARY_PATH=~/.local/lib64 myDemo
hello world!

何时使用 LD\_LIBRARY\_PATH

在大多数情况下,LD_LIBRARY_PATH 不是你需要设置的变量。按照设计,库安装到 /usr/lib64 中,因此应用自然会在其中搜索所需的库。在两种情况下,你可能需要使用 LD_LIBRARY_PATH

  • 你正在编译的软件需要链接到本身刚刚编译但尚未安装的库。良好设计的构建系统,例如 AutotoolsCMake,可以帮助处理这个问题。
  • 你正在使用设计为在单个目录之外运行的软件,它没有安装脚本,或安装脚本将库放置在非标准目录中。一些应用具有 Linux 用户可以下载、复制到 /opt 并在“不安装”的情况下运行的版本。LD_PATH_LIBRARY 变量是通过封装脚本设置的,因此用户通常甚至不知道它已被设置。

编译软件为你在运行系统方面提供了很大的灵活性。LD_LIBRARY_PATH 变量以及 -L-l GCC 选项是这种灵活性的组成部分。


via: https://opensource.com/article/22/5/compile-code-ldlibrarypath

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

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

使用开源预算工具 Skrooge 让你的财务管理更加轻松。

 title=

2021 年,人们喜欢 Linux 的理由比以往任何时候都多。在本系列中,我将分享使用 Linux 的 21 个不同理由。本篇介绍的是个人财务管理。

个人财务可能很难管理。当你没有足够的钱在没有经济援助的情况下度日时,这可能是令人沮丧甚至不安的,而当你确实有所需的钱却又不清楚每个月的去向时,这可能会令人惊讶地难以接受。更糟糕的是,我们经常被告知要“制定预算”,好像宣布你每个月的花销就能在某种程度上体现出你需要多少钱。底线是:制定预算是困难的,没有达到你的财务目标是令人沮丧的。但这仍然很重要,Linux 有几个工具可以帮助使任务变得可管理。

理财

就像生活中的其他事情一样,我们都有自己的方法来跟踪我们的财务。我过去常常采取一种简单而直接的方法:我的薪水支票被存入一个账户,然后我会提取一定比例的现金。一旦我钱包里的钱没了,我就得等到下一个发薪日才能花钱。我用了一天没有午餐的时间,就明白了我必须认真对待我的目标,并相应地调整了我的消费行为。对于当时我的简单的生活方式来说,这是一种让我对自己的收入保持诚实的有效手段,但它并不能很好地转化为在线商业交易、长期公用事业合同、投资等等。

随着我不断完善我的财务跟踪方式,我了解到个人会计始终是一个不断发展的过程。我们每个人都有独特的财务状况,这告诉我们可以或应该使用什么样的解决方案来跟踪我们的收入和债务。如果你失业了,那么你的预算目标可能是尽可能少花钱。如果你在工作,但在还学生贷款,那么你的目标可能是向银行汇款。如果你在工作,但计划退休,那么你可能会尽可能多地存钱。

关于预算,要记住的一点是,它是为了将你的财务现实与你的财务 目标 进行比较。你无法避免一些开支,但在这些之后,你可以设定自己的优先事项。如果你没有达到你的目标,你可以调整自己的行为或改写你的目标,使其更好地反映现实。调整你的财务计划并不意味着你失败了,这只是意味着你最初的预测并不准确。在困难时期,你可能无法达到任何预算目标,但如果你坚持你的预算,你会学到很多关于维持你目前的生活方式(无论它是什么)所需要的财务手段。随着时间的推移,你可以学习调整你可能从未意识到的变化。例如,由于远程工作已成为一种被广泛接受的选择,人们正在搬到农村城镇以降低生活成本。看到这样一种生活方式的转变可以改变你的预算报告,真是令人震惊。

重点是,预算编制是一项经常被低估的活动,这在很大程度上是因为它令人生畏。重要的是要认识到,无论你的专业水平或对财务的兴趣如何,你都可以进行预算。无论你 只使用 LibreOffice 电子表格,还是尝试专用的财务应用程序,你都可以设定目标,跟踪自己的行为,并学到许多宝贵的经验教训,这些经验教训最终可能会带来回报。

开源会计

有几个专用于 Linux 的个人理财应用程序,包括 HomeBankMoney Manager EXGNUCashKMyMoneySkrooge。所有这些应用程序本质上都是账本,你可以在每个月底(或每当你查看帐户时)退回到一个地方,从你的银行导入数据,并审查你的支出如何与你为自己设定的预算保持一致。

显示财务数据的 Skrooge 界面

我使用 Skrooge 作为我的个人预算跟踪器。即便面对多个银行账户,它也能轻松自如的设置。与大多数开源金融应用程序一样,Skrooge 可以导入多种文件格式,因此我的工作流程大致如下:

  1. 登录我的银行。
  2. 将当月的银行对账单导出为 QIF 文件。
  3. 打开 Skrooge。
  4. 导入 QIF 文件。每个文件都会自动分配到相应的帐户。
  5. 对照我为自己设定的预算目标审查我的支出。如果我超支了,那么我就会扣减下个月的目标(这样我就会理性地少花钱来弥补差额)。如果我尚未超出我的目标预算,那么我会把多余的部分移到 12 月的预算中(这样我在年底就会有更多的支出份额)。

我只跟踪了 Skrooge 中的家庭预算的一部分。Skrooge 通过一个动态数据库简化了这一过程,该数据库允许我使用自定义标签一次对多个交易进行分类。这使我可以轻松地从一般家庭和公用事业支出中提取我的个人支出,并且我可以在查看 Skrooge 提供的自动生成的报告时利用这些类别。

Skrooge 预算饼图

最重要的是,流行的 Linux 财务应用程序使我能够以最适合我的方式管理我的预算。例如,我的合作伙伴更喜欢使用 LibreOffice 电子表格,但我只需要付出很少的努力就可以从家庭预算中提取 CSV 文件,将其导入到 Skrooge,并使用一组更新的数据集。不存在供应商锁定和不兼容。该系统灵活敏捷,使我们能够在更多地了解有效预算和生活中的情况时调整我们的预算和跟踪支出的方法。

开放选择

世界各地的货币市场各不相同,我们每个人与之互动的方式也决定了我们可以使用哪些工具。归根结底,你对财务类软件的选择必须基于自己的需求。开源做得特别好的一件事是为用户提供了选择的自由。

在设定自己的财务目标时,我很欣赏我可以使用最适合我个人计算风格的任何应用程序。我可以控制我在生活中如何处理数据,即使是我不一定喜欢处理的数据。Linux 及其令人惊叹的应用程序集使它不再是一件苦差事。

在 Linux 上尝试一些财务应用程序,看看你是否可以激励自己设定一些目标并节省开支吧!


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

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

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

以下是切换到 Linux sudo 命令的五个安全原因。下载 sudo 参考手册获取更多技巧。

在传统的 Unix 和类 Unix 系统上,新系统中存在的第一个同时也是唯一的用户是 root。使用 root 账户登录并创建“普通”用户。在初始化之后,你应该以普通用户身份登录。

以普通用户身份使用系统是一种自我施加的限制,可以防止愚蠢的错误。例如,作为普通用户,你不能删除定义网络接口的配置文件或意外覆盖用户和组列表。作为普通用户,你无权访问这些重要文件,所以你无法犯这些错误。作为系统的实际所有者,你始终可以通过 su 命令切换为超级用户(root)并做你想做的任何事情,但对于日常工作,你应该使用普通账户。

几十年来,su 运行良好,但随后出现了 sudo 命令。

对于日常使用超级用户的人来说,sudo 命令乍一看似乎是多余的。在某些方面,它感觉很像 su 命令。例如:

$ su root
<输入密码>
# dnf install -y cowsay

sudo 做同样的事情:

$ sudo dnf install -y cowsay
<输入密码>

它们的作用几乎完全相同。但是大多数发行版推荐使用 sudo 而不是 su,甚至大多数发行版已经完全取消了 root 账户(LCTT 译注:不是取消,而是默认禁止使用 root 用户进行登录、运行命令等操作。root 依然是 0 号用户,依然拥有大部分系统文件和在后台运行大多数服务)。让 Linux 变得愚蠢是一个阴谋吗?

事实并非如此。sudo 使 Linux 更加灵活和可配置,并且没有损失功能,此外还有 几个显著的优点

为什么在 Linux 上 sudo 比 root 更好?

以下是你应该使用 sudo 替换 su 的五个原因。

1. root 是被攻击确认的对象

我使用 防火墙fail2banSSH 密钥 的常用组合来防止一些针对服务器的不必要访问。在我理解 sudo 的价值之前,我对日志中的暴力破解感到恐惧。自动尝试以 root 身份登录是最常见的情况,自然这是有充分理由的。

有一定入侵常识的攻击者应该知道,在广泛使用 sudo 之前,基本上每个 Unix 和 Linux 都有一个 root 账户。这样攻击者就会少一种猜测。因为登录名总是正确的,只要它是 root 就行,所以攻击者只需要一个有效的密码。

删除 root 账户可提供大量保护。如果没有 root,服务器就没有确认的登录账户。攻击者必须猜测登录名以及密码。这不是两次猜测,而是两个必须同时正确的猜测。(LCTT 译注:此处是误导,root 用户不可删除,否则系统将会出现问题。另外,虽然 root 可以改名,但是也最好不要这样做,因为很多程序内部硬编码了 root 用户名。可以禁用 root 用户,给它一个不能登录的密码。)

2. root 是最终的攻击媒介

在访问失败日志中经常可以见到 root 用户,因为它是最强大的用户。如果你要设置一个脚本强行进入他人的服务器,为什么要浪费时间尝试以受限的普通用户进入呢?只有最强大的用户才有意义。

root 既是唯一已知的用户名,又是最强大的用户账户。因此,root 基本上使尝试暴力破解其他任何东西变得毫无意义。

3. 可选择的权限

su 命令要么全有要么全没有。如果你有 su root 的密码,你就可以变成超级用户。如果你没有 su 的密码,那么你就没有任何管理员权限。这个模型的问题在于,系统管理员必须在将 root 密钥移交或保留密钥和对系统的所有权之间做出选择。这并不总是你想要的,有时候你只是想授权而已

例如,假设你想授予用户以 root 身份运行特定应用程序的权限,但你不想为用户提供 root 密码。通过编辑 sudo 配置,你可以允许指定用户,或属于指定 Unix 组的任何用户运行特定命令。sudo 命令需要用户的现有密码,而不是你的密码,当然也不是 root 密码。

4.超时

使用 sudo 运行命令后,通过身份验证的用户的权限会提升 5 分钟。在此期间,他们可以运行任何管理员授权的命令。

5 分钟后,认证缓存被清空,下次使用 sudo 再次提示输入密码。超时可防止用户意外执行某些操作(例如,搜索 shell 历史记录时不小心或按多了向上箭头)。如果一个用户离开办公桌而没有锁定计算机屏幕,它还可以确保另一个用户不能运行这些命令。

5. 日志记录

Shell 历史功能可以作为一个用户所做事情的日志。如果你需要了解系统发生了什么,你可以(理论上,取决于 shell 历史记录的配置方式)使用 su 切换到其他人的账户,查看他们的 shell 历史记录,也可以了解用户执行了哪些命令。

但是,如果你需要审计 10 或 100 名用户的行为,你可能会注意到此方法无法扩展。Shell 历史记录的轮转速度很快,默认为 1000 条,并且可以通过在任何命令前加上空格来轻松绕过它们。

当你需要管理任务的日志时,sudo 提供了一个完整的 日志记录和警报子系统,因此你可以在一个特定位置查看活动,甚至在发生重大事件时获得警报。

学习 sudo 其他功能

除了本文列举的一些功能,sudo 命令还有很多已有的或正在开发中的新功能。因为 sudo 通常是你配置一次然后就忘记的东西,或者只在新管理员加入团队时才配置的东西,所以很难记住它的细微差别。

下载 sudo 参考手册,在你最需要的时候把它当作一个有用的指导书。

sudo 参考手册

via: https://opensource.com/article/22/5/use-sudo-linux

作者:Seth Kenlon 选题:lkxed 译者:MjSeven 校对:turbokernel

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

正在寻找新的文本编辑器?这里有 30 个编辑器可供尝试。

 title=

计算机是基于文本的,因此你使用它们做的事情越多,你可能就越需要文本编辑应用程序。你在文本编辑器上花费的时间越多,你就越有可能对你使用的编辑器提出更多的要求。

如果你正在寻找一个好的文本编辑器,你会发现 Linux 可以提供很多。无论你是想在终端、桌面还是在云端工作,你都可以试一试。你可以每天一款编辑器,连续着试一个月(或每月试一个,能够试三年)。坚持不懈,你终将找到适合你的完美的编辑器。

Vim 类编辑器

  • Vi 通常随着 Linux 各发行版、BSD、Solaris 和 macOS 一起安装。它是典型的 Unix 文本编辑器,具有编辑模式和超高效的单键快捷键的独特组合。最初的 Vi 编辑器由 Bill Joy 编写(他也是 C shell 的作者)。Vi 的现代版本,尤其是 Vim,增加了许多特性,包括多级撤消、在插入模式下更好的导航、行折叠、语法高亮、插件支持等等。但它需要学习如何使用(它甚至有自己的教程程序,vimtutor)。
  • Kakoune 是一个受 Vim 启发的应用程序,它具有熟悉的简约界面、短键盘快捷键以及独立的编辑和插入模式。乍一看,它的外观和感觉很像 Vi,但它在设计和功能上有自己独特的风格。 它有一个小彩蛋:具有 Clippy 界面的实现。

emacs 编辑器

  • 从最初的免费 emacs 开始,发展到发起了自由软件运动的 GNU 项目的第一批官方应用程序,GNU Emacs 是一个广受欢迎的文本编辑器。它非常适合系统管理员、开发人员和日常用户的使用,具有大量功能和近乎无穷无尽的扩展。一旦你开始使用 emacs,你可能会发现很难想出一个理由来关闭它,因为它能做的事情非常多!
  • 如果你喜欢 emacs,但觉得 GNU Emacs 过于臃肿,那么你可以试试 Jove。Jove 是一个基于终端的 emacs 编辑器。它很容易使用,但是如果你是使用 emacs 编辑器家族的新手,那么 Jove 也是很容易学习的,这要归功于 teajove 命令。
  • 另一个轻量级的 emacs 编辑器是 Jed。它的工作流程基于宏。它与其他编辑器的不同之处在于它使用了 S-Lang,这是一种类似 C 的脚本语言,它为使用 C 而不是使用 Lisp 的开发人员提供了扩展的机会。

交互式编辑器

  • GNU nano 对基于终端的文本编辑采取了大胆的立场:它提供了一个菜单。是的,这个不起眼的编辑器从 GUI 编辑器那里得到了提示,它告诉用户他们需要按哪个键来执行特定的功能。这是一种令人耳目一新的用户体验,所以难怪 nano 被设置为“用户友好”发行版的默认编辑器,而不是 Vi。
  • JOE 基于一个名为 WordStar 的旧文本编辑应用程序。如果你不熟悉 Wordstar,JOE 也可以模仿 Emacs 或 GNU nano。默认情况下,它是介于 Emacs 或 Vi 等相对神秘的编辑器和 GNU Nano 永远显示的冗长信息之间的一个很好的折衷方案(例如,它告诉你如何激活屏幕帮助显示,但默认情况下不启用)。
  • e3 是一个优秀的小型文本编辑器,具有五个内置的键盘快捷键方案,用来模拟 Emacs、Vi、nano、NEdit 和 WordStar。换句话说,无论你习惯使用哪种基于终端的编辑器,你都可能对 e3 感到宾至如归。

ed 及像 ed 一样的编辑器

  • POSIX 和 Open Group 定义了基于 Unix 的操作系统的标准,ed 行编辑器是它的一部分。它安装在你遇到的几乎所有 Linux 或 Unix 系统上。它小巧、简洁、一流。
  • 基于 ed,Sed 流编辑器因其功能和语法而广受欢迎。大多数 Linux 用户在搜索如何最简单、最快捷的更新配置文件中的行的方法时,至少会遇到一个 sed 命令,但它值得仔细研究一下。Sed 是一个强大的命令,包含许多有用的子命令。更好地了解了它,你可能会发现自己打开文本编辑器应用程序的频率要低得多。
  • 你并不总是需要文本编辑器来编辑文本。heredoc(或 Here Doc)系统可在任何 POSIX 终端中使用,允许你直接在打开的终端中输入文本,然后将输入的内容通过管道传输到文本文件中。这不是最强大的编辑体验,但它用途广泛且始终可用。

极简风格的编辑器

如果你认为一个好的文本编辑器就是一个文字处理器(除了没有所有的处理功能)的话,你可能正在寻找这些经典编辑器。这些编辑器可让你以最少的干扰和最少的帮助写作和编辑文本。它们提供的功能通常以标记文本、Markdown 或代码为中心。有些名称遵循某种模式:

  • Gedit 来自 GNOME 团队;
  • medit 有经典的 GNOME 手感;
  • Xedit 仅使用最基本的 X11 库;
  • jEdit 适用于 Java 爱好者。

KDE 用户也有类似的:

  • Kate 是一款低调的编辑器,拥有你需要的几乎所有功能;
  • KWrite 在看似简单易用的界面中隐藏了大量有用的功能。

还有一些适用于其他平台:

  • Pe 适用于 Haiku OS(90 年代那个古怪的孩子 BeOS 的转世);
  • FeatherPad 是适用于 Linux 的基本编辑器,但对 macOS 和 Haiku 有一些支持。如果你是一名希望移植代码的 Qt 黑客,请务必看一看!

集成开发环境(IDE)

文本编辑器和集成开发环境(IDE)有很多相同之处。后者实际上只是前者加上许多为特定代码而添加的功能。如果你经常使用 IDE,你可能会在扩展管理器中发现一个 XML 或 Markdown 编辑器:

  • NetBeans 是一个方便 Java 用户的文本编辑器。
  • Eclipse 提供了一个强大的编辑套件,其中包含许多扩展,可为你提供所需的工具。

云端编辑器

在云端工作?当然,你也可以在那里进行编辑。

  • Etherpad 是在网上运行的文本编辑器应用程序。有独立免费的实例供你使用,或者你也可以设置自己的实例。
  • Nextcloud 拥有蓬勃发展的应用场景,包括内置文本编辑器和具有实时预览功能的第三方 Markdown 编辑器。

较新的编辑器

每个人都会有让文本编辑器变得更完美的想法。因此,几乎每年都会发布新的编辑器。有些以一种新的、令人兴奋的方式重新实现经典的旧想法,有些对用户体验有独特的看法,还有些则专注于特定的需求。

  • Atom 是来自 GitHub 的多功能的现代文本编辑器,具有许多扩展和 Git 集成。
  • Brackets 是 Adobe 为 Web 开发人员提供的编辑器。
  • Focuswriter 旨在通过无干扰的全屏模式、可选的打字机音效和精美的配置选项等有用功能帮助你专注于写作。
  • Howl 是一个基于 Lua 和 Moonscript 的渐进式动态编辑器。
  • NorkaKJots 模仿笔记本,每个文档代表“活页夹”中的“页面”。你可以通过导出功能从笔记本中取出单个页面。

自己制作编辑器

俗话说得好:既然可以编写自己的应用程序,为什么要使用别人的(虽然其实没有这句俗语)?虽然 Linux 有超过 30 个常用的文本编辑器,但是再说一次,开源的一部分乐趣在于能够亲手进行实验。

如果你正在寻找学习编程的理由,那么制作自己的文本编辑器是一个很好的入门方法。你可以在大约 100 行代码中实现基础功能,并且你使用它的次数越多,你可能就越会受到启发,进而去学习更多知识,从而进行改进。准备好开始了吗?来吧,去 创建你自己的文本编辑器


via: https://opensource.com/article/21/2/open-source-text-editors

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

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