分类 技术 下的文章

那些令人怀念的经典游戏可是提高编程能力的好素材。今天就让我们仔细探索一番,怎么用 Bash 编写一个扫雷程序。

我在编程教学方面不是专家,但当我想更好掌握某一样东西时,会试着找出让自己乐在其中的方法。比方说,当我想在 shell 编程方面更进一步时,我决定用 Bash 编写一个扫雷)游戏来加以练习。

如果你是一个有经验的 Bash 程序员,希望在提高技巧的同时乐在其中,那么请跟着我编写一个你的运行在终端中的扫雷游戏。完整代码可以在这个 GitHub 存储库中找到。

做好准备

在我编写任何代码之前,我列出了该游戏所必须的几个部分:

  1. 显示雷区
  2. 创建游戏逻辑
  3. 创建判断单元格是否可选的逻辑
  4. 记录可用和已查明(已排雷)单元格的个数
  5. 创建游戏结束逻辑

显示雷区

在扫雷中,游戏界面是一个由 2D 数组(列和行)组成的不透明小方格。每一格下都有可能藏有地雷。玩家的任务就是找到那些不含雷的方格,并且在这一过程中,不能点到地雷。这个 Bash 版本的扫雷使用 10x10 的矩阵,实际逻辑则由一个简单的 Bash 数组来完成。

首先,我先生成了一些随机数字。这将是地雷在雷区里的位置。控制地雷的数量,在开始编写代码之前,这么做会容易一些。实现这一功能的逻辑可以更好,但我这么做,是为了让游戏实现保持简洁,并有改进空间。(我编写这个游戏纯属娱乐,但如果你能将它修改的更好,我也是很乐意的。)

下面这些变量在整个过程中是不变的,声明它们是为了随机生成数字。就像下面的 a - g 的变量,它们会被用来计算可排除的地雷的值:

# 变量
score=0 # 会用来存放游戏分数
# 下面这些变量,用来随机生成可排除地雷的实际值
a="1 10 -10 -1"
b="-1 0 1"
c="0 1"
d="-1 0 1 -2 -3"
e="1 2 20 21 10 0 -10 -20 -23 -2 -1"
f="1 2 3 35 30 20 22 10 0 -10 -20 -25 -30 -35 -3 -2 -1"
g="1 4 6 9 10 15 20 25 30 -30 -24 -11 -10 -9 -8 -7"
#
# 声明
declare -a room  # 声明一个 room 数组,它用来表示雷区的每一格。

接下来,我会用列(0-9)和行(a-j)显示出游戏界面,并且使用一个 10x10 矩阵作为雷区。(M[10][10] 是一个索引从 0-99,有 100 个值的数组。) 如想了解更多关于 Bash 数组的内容,请阅读这本书那些关于 Bash 你所不了解的事: Bash 数组简介

创建一个叫 plough 的函数,我们先将标题显示出来:两个空行、列头,和一行 -,以示意往下是游戏界面:

printf '\n\n'
printf '%s' "     a   b   c   d   e   f   g   h   i   j"
printf '\n   %s\n' "-----------------------------------------"

然后,我初始化一个计数器变量,叫 r,它会用来记录已显示多少横行。注意,稍后在游戏代码中,我们会用同一个变量 r,作为我们的数组索引。 在 Bash for 循环中,用 seq 命令从 0 增加到 9。我用数字(d%)占位,来显示行号($row,由 seq 定义):

r=0 # 计数器
for row in $(seq 0 9); do
  printf '%d  ' "$row" # 显示 行数 0-9 

在我们接着往下做之前,让我们看看到现在都做了什么。我们先横着显示 [a-j] 然后再将 [0-9] 的行号显示出来,我们会用这两个范围,来确定用户排雷的确切位置。

接着,在每行中,插入列,所以是时候写一个新的 for 循环了。这一循环管理着每一列,也就是说,实际上是生成游戏界面的每一格。我添加了一些辅助函数,你能在源码中看到它的完整实现。 对每一格来说,我们需要一些让它看起来像地雷的东西,所以我们先用一个点(.)来初始化空格。为了实现这一想法,我们用的是一个叫 is_null_field 的自定义函数。 同时,我们需要一个存储每一格具体值的数组,这儿会用到之前已定义的全局数组 room , 并用 变量 r作为索引。随着 r 的增加,遍历所有单元格,并随机部署地雷。

  for col in $(seq 0 9); do
    ((r+=1))  # 循环完一列行数加一
    is_null_field $r  #  假设这里有个函数,它会检查单元格是否为空,为真,则此单元格初始值为点(.)
    printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}" #  最后显示分隔符,注意,${room[$r]} 的第一个值为 '.',等于其初始值。
  #结束 col 循环
  done

最后,为了保持游戏界面整齐好看,我会在每行用一个竖线作为结尾,并在最后结束行循环:

printf '%s\n' "|"   # 显示出行分隔符
printf '   %s\n' "-----------------------------------------"
# 结束行循环
done
printf '\n\n'

完整的 plough 代码如下:

plough()
{
  r=0
  printf '\n\n'
  printf '%s' "     a   b   c   d   e   f   g   h   i   j"
  printf '\n   %s\n' "-----------------------------------------"
  for row in $(seq 0 9); do
    printf '%d  ' "$row"
    for col in $(seq 0 9); do
       ((r+=1))
       is_null_field $r
       printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}"
    done
    printf '%s\n' "|"
    printf '   %s\n' "-----------------------------------------"
  done
  printf '\n\n'
}

我花了点时间来思考,is_null_field 的具体功能是什么。让我们来看看,它到底能做些什么。在最开始,我们需要游戏有一个固定的状态。你可以随便选择个初始值,可以是一个数字或者任意字符。我最后决定,所有单元格的初始值为一个点(.),因为我觉得,这样会让游戏界面更好看。下面就是这一函数的完整代码:

is_null_field()
{
  local e=$1 # 在数组 room 中,我们已经用过循环变量 'r' 了,这次我们用 'e'
    if [[ -z "${room[$e]}" ]];then
      room[$r]="."  #这里用点(.)来初始化每一个单元格
    fi
}

现在,我已经初始化了所有的格子,现在只要用一个很简单的函数就能得出当前游戏中还有多少单元格可以操作:

get_free_fields()
{
  free_fields=0    # 初始化变量 
  for n in $(seq 1 ${#room[@]}); do
    if [[ "${room[$n]}" = "." ]]; then  # 检查当前单元格是否等于初始值(.),结果为真,则记为空余格子。 
      ((free_fields+=1))
    fi
  done
}

这是显示出来的游戏界面,[a-j] 为列,[0-9] 为行。

 title=

创建玩家逻辑

玩家操作背后的逻辑在于,先从 stdin) 中读取数据作为坐标,然后再找出对应位置实际包含的值。这里用到了 Bash 的参数扩展,来设法得到行列数。然后将代表列数的字母传给分支语句,从而得到其对应的列数。为了更好地理解这一过程,可以看看下面这段代码中,变量 o 所对应的值。 举个例子,玩家输入了 c3,这时 Bash 将其分成两个字符:c3。为了简单起见,我跳过了如何处理无效输入的部分。

  colm=${opt:0:1}  # 得到第一个字符,一个字母
  ro=${opt:1:1}    # 得到第二个字符,一个整数
  case $colm in
    a ) o=1;;      # 最后,通过字母得到对应列数。
    b ) o=2;;
    c ) o=3;;
    d ) o=4;;
    e ) o=5;;
    f ) o=6;;
    g ) o=7;;
    h ) o=8;;
    i ) o=9;;
    j ) o=10;;
  esac

下面的代码会计算用户所选单元格实际对应的数字,然后将结果储存在变量中。

这里也用到了很多的 shuf 命令,shuf 是一个专门用来生成随机序列的 Linux 命令-i 选项后面需要提供需要打乱的数或者范围,-n 选项则规定输出结果最多需要返回几个值。Bash 中,可以在两个圆括号内进行数学计算,这里我们会多次用到。

还是沿用之前的例子,玩家输入了 c3。 接着,它被转化成了 ro=3o=3。 之后,通过上面的分支语句代码, 将 c 转化为对应的整数,带进公式,以得到最终结果 i 的值。

  i=$(((ro*10)+o))   # 遵循运算规则,算出最终值
  is_free_field $i $(shuf -i 0-5 -n 1)   #  调用自定义函数,判断其指向空/可选择单元格。

仔细观察这个计算过程,看看最终结果 i 是如何计算出来的:

i=$(((ro*10)+o))
i=$(((3*10)+3))=$((30+3))=33

最后结果是 33。在我们的游戏界面显示出来,玩家输入坐标指向了第 33 个单元格,也就是在第 3 行(从 0 开始,否则这里变成 4),第 3 列。

创建判断单元格是否可选的逻辑

为了找到地雷,在将坐标转化,并找到实际位置之后,程序会检查这一单元格是否可选。如不可选,程序会显示一条警告信息,并要求玩家重新输入坐标。

在这段代码中,单元格是否可选,是由数组里对应的值是否为点(.)决定的。如果可选,则重置单元格对应的值,并更新分数。反之,因为其对应值不为点,则设置变量 not_allowed。为简单起见,游戏中警告消息这部分源码,我会留给读者们自己去探索。

is_free_field()
{
  local f=$1
  local val=$2
  not_allowed=0
  if [[ "${room[$f]}" = "." ]]; then
    room[$f]=$val
    score=$((score+val))
  else
    not_allowed=1
  fi
}

 title=

如输入坐标有效,且对应位置为地雷,如下图所示。玩家输入 h6,游戏界面会出现一些随机生成的值。在发现地雷后,这些值会被加入用户得分。

 title=

还记得我们开头定义的变量,a - g 吗,我会用它们来确定随机生成地雷的具体值。所以,根据玩家输入坐标,程序会根据(m)中随机生成的数,来生成周围其他单元格的值(如上图所示)。之后将所有值和初始输入坐标相加,最后结果放在 i(计算结果如上)中。

请注意下面代码中的 X,它是我们唯一的游戏结束标志。我们将它添加到随机列表中。在 shuf 命令的魔力下,X 可以在任意情况下出现,但如果你足够幸运的话,也可能一直不会出现。

m=$(shuf -e a b c d e f g X -n 1)   # 将 X 添加到随机列表中,当 m=X,游戏结束
  if [[ "$m" != "X" ]]; then        # X 将会是我们爆炸地雷(游戏结束)的触发标志
    for limit in ${!m}; do          # !m 代表 m 变量的值
      field=$(shuf -i 0-5 -n 1)     # 然后再次获得一个随机数字
      index=$((i+limit))            # 将 m 中的每一个值和 index 加起来,直到列表结尾
      is_free_field $index $field
    done

我想要游戏界面中,所有随机显示出来的单元格,都靠近玩家选择的单元格。

 title=

记录已选择和可用单元格的个数

这个程序需要记录游戏界面中哪些单元格是可选择的。否则,程序会一直让用户输入数据,即使所有单元格都被选中过。为了实现这一功能,我创建了一个叫 free_fields 的变量,初始值为 0。用一个 for 循环,记录下游戏界面中可选择单元格的数量。 如果单元格所对应的值为点(.),则 free_fields 加一。

get_free_fields()
{
  free_fields=0
  for n in $(seq 1 ${#room[@]}); do
    if [[ "${room[$n]}" = "." ]]; then
      ((free_fields+=1))
    fi
  done
}

等下,如果 free_fields=0 呢? 这意味着,玩家已选择过所有单元格。如果想更好理解这一部分,可以看看这里的源代码

if [[ $free_fields -eq 0 ]]; then   # 这意味着你已选择过所有格子
      printf '\n\n\t%s: %s %d\n\n' "You Win" "you scored" "$score"
      exit 0
fi

创建游戏结束逻辑

对于游戏结束这种情况,我们这里使用了一些很巧妙的技巧,将结果在屏幕中央显示出来。我把这部分留给读者朋友们自己去探索。

if [[ "$m" = "X" ]]; then
    g=0                      # 为了在参数扩展中使用它
    room[$i]=X               # 覆盖此位置原有的值,并将其赋值为X
    for j in {42..49}; do    # 在游戏界面中央,
      out="gameover"
      k=${out:$g:1}          # 在每一格中显示一个字母
      room[$j]=${k^^}
      ((g+=1))
    done
fi

最后,我们显示出玩家最关心的两行。

if [[ "$m" = "X" ]]; then
      printf '\n\n\t%s: %s %d\n' "GAMEOVER" "you scored" "$score"
      printf '\n\n\t%s\n\n' "You were just $free_fields mines away."
      exit 0
fi

 title=

文章到这里就结束了,朋友们!如果你想了解更多,具体可以查看我的 GitHub 存储库,那儿有这个扫雷游戏的源代码,并且你还能找到更多用 Bash 编写的游戏。 我希望,这篇文章能激起你学习 Bash 的兴趣,并乐在其中。


via: https://opensource.com/article/19/9/advanced-bash-building-minesweeper

作者:Abhishek Tamrakar 选题:lujun9972 译者:wenwensnow 校对:wxy

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

通常,Linux 管理员们都使用 history 命令来跟踪在先前的会话中执行过哪些命令,但是 history 命令的局限性在于它不存储命令的输出。在某些情况下,我们要检查上一个会话的命令输出,并希望将其与当前会话进行比较。除此之外,在某些情况下,我们正在对 Linux 生产环境中的问题进行故障排除,并希望保存所有终端会话活动以供将来参考,因此在这种情况下,script 命令就变得很方便。

script 是一个命令行工具,用于捕获/记录你的 Linux 服务器终端会话活动,以后可以使用 scriptreplay 命令重放记录的会话。在本文中,我们将演示如何安装 script 命令行工具以及如何记录 Linux 服务器终端会话活动,然后,我们将看到如何使用 scriptreplay 命令来重放记录的会话。

安装 script 工具

在 RHEL 7/ CentOS 7 上安装 script 工具

script 命令由 RPM 包 util-linux 提供,如果你没有在你的 CentOS 7 / RHEL 7 系统上安装它,运行下面的 yum 安装它:

[root@linuxtechi ~]# yum install util-linux -y

在 RHEL 8 / CentOS 8 上安装 script 工具

运行下面的 dnf 命令来在 RHEL 8 / CentOS 8 上安装 script 工具:

[root@linuxtechi ~]# dnf install util-linux -y

在基于 Debian 的系统(Ubuntu / Linux Mint)上安装 script 工具

运行下面的 apt-get 命令来安装 script 工具:

root@linuxtechi ~]# apt-get install util-linux -y

如何使用 script 工具

直接使用 script 命令,在终端上键入 script 命令,然后按回车,它将开始在名为 typescript 的文件中捕获当前的终端会话活动。

[root@linuxtechi ~]# script
Script started, file is typescript
[root@linuxtechi ~]#

要停止记录会话活动,请键入 exit 命令,然后按回车:

[root@linuxtechi ~]# exit
exit
Script done, file is typescript
[root@linuxtechi ~]#

script 命令的语法格式:

~] # script {options}  {file_name}

能在 script 命令中使用的不同选项:

options-script-command

让我们开始通过执行 script 命令来记录 Linux 终端会话,然后执行诸如 wroute -ndf -hfree -h,示例如下所示:

script-examples-linux-server

正如我们在上面看到的,终端会话日志保存在文件 typescript 中:

现在使用 cat / vi 命令查看 typescript 文件的内容,

[root@linuxtechi ~]# ls -l typescript
-rw-r--r--. 1 root root 1861 Jun 21 00:50 typescript
[root@linuxtechi ~]#

typescript-file-content-linux

以上内容确认了我们在终端上执行的所有命令都已保存在 typescript 文件中。

在 script 命令中使用定制文件名

假设我们要使用自定义文件名来执行 script 命令,可以在 script 命令后指定文件名。在下面的示例中,我们使用的文件名为 session-log-(当前日期时间).txt

[root@linuxtechi ~]# script sessions-log-$(date +%d-%m-%Y-%T).txt
Script started, file is sessions-log-21-06-2019-01:37:39.txt
[root@linuxtechi ~]#

现在运行该命令并输入 exit

[root@linuxtechi ~]# exit
exit
Script done, file is sessions-log-21-06-2019-01:37:39.txt
[root@linuxtechi ~]#

附加命令输出到 script 记录文件

假设 script 命令已经将命令输出记录到名为 session-log.txt 的文件中,现在我们想将新会话命令的输出附加到该文件中,那么可以在 script 命令中使用 -a 选项。

[root@linuxtechi ~]# script -a sessions-log.txt
Script started, file is sessions-log.txt
[root@linuxtechi ~]# xfs_info /dev/mapper/centos-root
meta-data=/dev/mapper/centos-root isize=512    agcount=4, agsize=2746624 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0 spinodes=0
data     =                       bsize=4096   blocks=10986496, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal               bsize=4096   blocks=5364, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
[root@linuxtechi ~]# exit
exit
Script done, file is sessions-log.txt
[root@linuxtechi ~]#

要查看更新的会话记录,使用 cat session-log.txt 命令。

无需 shell 交互而捕获命令输出到 script 记录文件

假设我们要捕获命令的输出到会话记录文件,那么使用 -c 选项,示例如下所示:

[root@linuxtechi ~]# script -c "uptime && hostname && date" root-session.txt
Script started, file is root-session.txt
 01:57:40 up  2:30,  3 users,  load average: 0.00, 0.01, 0.05
linuxtechi
Fri Jun 21 01:57:40 EDT 2019
Script done, file is root-session.txt
[root@linuxtechi ~]#

以静默模式运行 script 命令

要以静默模式运行 script 命令,请使用 -q 选项,该选项将禁止 script 的启动和完成消息,示例如下所示:

[root@linuxtechi ~]# script -c "uptime && date" -q root-session.txt
 02:01:10 up  2:33,  3 users,  load average: 0.00, 0.01, 0.05
Fri Jun 21 02:01:10 EDT 2019
[root@linuxtechi ~]#

要将时序信息记录到文件中并捕获命令输出到单独的文件中,这可以通过在 script 命令中传递时序文件(-timing)实现,示例如下所示:

语法格式:

~ ]# script -t <timing-file-name>  {file_name}
[root@linuxtechi ~]# script --timing=timing.txt session.log
Script started, file is session.log
[root@linuxtechi ~]# uptime
 02:27:59 up  3:00,  3 users,  load average: 0.00, 0.01, 0.05
[root@linuxtechi ~]# date
Fri Jun 21 02:28:02 EDT 2019
[root@linuxtechi ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           3.9G        171M        2.0G        8.6M        1.7G        3.3G
Swap:          3.9G          0B        3.9G
[root@linuxtechi ~]# whoami
root
[root@linuxtechi ~]# exit
exit
Script done, file is session.log
[root@linuxtechi ~]#
[root@linuxtechi ~]# ls -l session.log timing.txt
-rw-r--r--. 1 root root 673 Jun 21 02:28 session.log
-rw-r--r--. 1 root root 414 Jun 21 02:28 timing.txt
[root@linuxtechi ~]#

重放记录的 Linux 终端会话活动

现在,使用 scriptreplay 命令重放录制的终端会话活动。

注意:scriptreplay 也由 RPM 包 util-linux 提供。scriptreplay 命令需要时序文件才能工作。

[root@linuxtechi ~]# scriptreplay --timing=timing.txt session.log

上面命令的输出将如下所示,

记录所有用户的 Linux 终端会话活动

在某些关键业务的 Linux 服务器上,我们希望跟踪所有用户的活动,这可以使用 script 命令来完成,将以下内容放在 /etc/profile 文件中,

[root@linuxtechi ~]# vi /etc/profile
……………………………………………………
if [ "x$SESSION_RECORD" = "x" ]
then
timestamp=$(date +%d-%m-%Y-%T)
session_log=/var/log/session/session.$USER.$$.$timestamp
SESSION_RECORD=started
export SESSION_RECORD
script -t -f -q 2>${session_log}.timing $session_log
exit
fi
……………………………………………………

保存文件并退出。

/var/log 文件夹下创建 session 目录:

[root@linuxtechi ~]# mkdir /var/log/session

给该文件夹指定权限:

[root@linuxtechi ~]# chmod 777 /var/log/session/
[root@linuxtechi ~]#

现在,验证以上代码是否有效。在我正在使用 pkumar 用户的情况下,登录普通用户到 Linux 服务器:

~ ] # ssh root@linuxtechi
root@linuxtechi's password:
[root@linuxtechi ~]$ uptime
 04:34:09 up  5:06,  3 users,  load average: 0.00, 0.01, 0.05
[root@linuxtechi ~]$ date
Fri Jun 21 04:34:11 EDT 2019
[root@linuxtechi ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:           3.9G        172M        2.0G        8.6M        1.7G        3.3G
Swap:          3.9G          0B        3.9G
[root@linuxtechi ~]$ id
uid=1001(pkumar) gid=1002(pkumar) groups=1002(pkumar) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@linuxtechi ~]$ whoami
pkumar
[root@linuxtechi ~]$ exit

Login as root and view user’s linux terminal session activity

[root@linuxtechi ~]# cd /var/log/session/
[root@linuxtechi session]# ls -l | grep pkumar
-rw-rw-r--. 1 pkumar pkumar 870 Jun 21 04:34 session.pkumar.19785.21-06-2019-04:34:05
-rw-rw-r--. 1 pkumar pkumar 494 Jun 21 04:34 session.pkumar.19785.21-06-2019-04:34:05.timing
[root@linuxtechi session]#

Session-output-file-linux

我们还可以使用 scriptreplay 命令来重放用户的终端会话活动:

[root@linuxtechi session]# scriptreplay --timing session.pkumar.19785.21-06-2019-04\:34\:05.timing session.pkumar.19785.21-06-2019-04\:34\:05

以上就是本教程的全部内容,请在下面的评论部分中分享你的反馈和评论。


via: https://www.linuxtechi.com/record-replay-linux-terminal-sessions-activity/

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

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

也许你并不需要编译 Linux 内核,但你能通过这篇教程快速上手。

在计算机世界里, 内核 kernel 是处理硬件与一般系统之间通信的 低阶软件 low-level software 。除过一些烧录进计算机主板的初始固件,当你启动计算机时,内核让系统意识到它有一个硬盘驱动器、屏幕、键盘以及网卡。分配给每个部件相等时间(或多或少)使得图像、音频、文件系统和网络可以流畅甚至并行地运行。

然而,对于硬件的需求是源源不断的,随着发布的硬件越多,内核就必须纳入更多代码来保证那些硬件正常工作。得到具体的数字很困难,但是 Linux 内核无疑是硬件兼容性方面的顶级内核之一。Linux 操作着无数的计算机和移动电话、工业用途和爱好者使用的板级嵌入式系统(SoC)、RAID 卡、缝纫机等等。

回到 20 世纪(甚至是 21 世纪初期),对于 Linux 用户来说,在刚买到新的硬件后就需要下载最新的内核代码并编译安装才能使用这是不可理喻的。而现在你也很难见到 Linux 用户为了好玩而编译内核或通过高度专业化定制的硬件的方式赚钱。现在,通常已经不需要再编译 Linux 内核了。

这里列出了一些原因以及快速编译内核的教程。

更新当前的内核

无论你买了配备新显卡或 Wifi 芯片集的新品牌电脑还是给家里配备一个新的打印机,你的操作系统(称为 GNU+Linux 或 Linux,它也是该内核的名字)需要一个驱动程序来打开新部件(显卡、芯片集、打印机和其他任何东西)的信道。有时候当你插入某些新的设备时而你的电脑表示发现了它,这具有一定的欺骗性。别被骗到了,有时候那就够了,但更多的情况是你的操作系统仅仅是使用了通用的协议检测到安装了新的设备。

例如,你的计算机也许能够鉴别出新的网络打印机,但有时候那仅仅是因为打印机的网卡被设计成为了获得 DHCP 地址而在网络上标识自己。它并不意味着你的计算机知道如何发送文档给打印机进行打印。事实上,你可以认为计算机甚至不“知道”那台设备是一个打印机。它也许仅仅是显示网络有个设备在一个特定的地址上,并且该设备以一系列字符 “p-r-i-n-t-e-r” 标识自己而已。人类语言的便利性对于计算机毫无意义。计算机需要的是一个驱动程序。

内核开发者、硬件制造商、技术支持和爱好者都知道新的硬件会不断地发布。它们大多数都会贡献驱动程序,直接提交给内核开发团队以包含在 Linux 中。例如,英伟达显卡驱动程序通常都会写入 Nouveau 内核模块中,并且因为英伟达显卡很常用,它的代码都包含在任一个日常使用的发行版内核中(例如当下载 FedoraUbuntu 得到的内核)。英伟达也有不常用的地方,例如嵌入式系统中 Nouveau 模块通常被移除。对其他设备来说也有类似的模块:打印机得益于 FoomaticCUPS,无线网卡有 b43、ath9k、wl 模块等等。

发行版往往会在它们 Linux 内核的构建中包含尽可能多合理的驱动程序,因为他们想让你在接入新设备时不用安装驱动程序能够立即使用。对于大多数情况来说就是这样的,尤其是现在很多设备厂商都在资助自己售卖硬件的 Linux 驱动程序开发,并且直接将这些驱动程序提交给内核团队以用在通常的发行版上。

有时候,或许你正在运行六个月之前安装的内核,并配备了上周刚刚上市令人兴奋的新设备。在这种情况下,你的内核也许没有那款设备的驱动程序。好消息是经常会出现那款设备的驱动程序已经存在于最近版本的内核中,意味着你只要更新运行的内核就可以了。

通常,这些都是通过安装包管理软件完成的。例如在 RHEL、CentOS 和 Fedora 上:

$ sudo dnf update kernel

在 Debian 和 Ubuntu 上,首先获取你当前内核的版本:

$ uname -r
4.4.186

搜索新的版本:

$ sudo apt update
$ sudo apt search linux-image

安装找到的最新版本。在这个例子中,最新的版本是 5.2.4:

$ sudo apt install linux-image-5.2.4

内核更新后,你必须 reboot (除非你使用 kpatch 或 kgraft)。这时,如果你需要的设备驱动程序包含在最新的内核中,你的硬件就会正常工作。

安装内核模块

有时候一个发行版没有预计到用户会使用某个设备(或者该设备的驱动程序至少不足以包含在 Linux 内核中)。Linux 对于驱动程序采用模块化方式,因此尽管驱动程序没有编译进内核,但发行版可以推送单独的驱动程序包让内核去加载。尽管有些复杂但是非常有用,尤其是当驱动程序没有包含进内核中而是在引导过程中加载,或是内核中的驱动程序相比模块化的驱动程序过期时。第一个问题可以用 “initrd” 解决(初始化 RAM 磁盘),这一点超出了本文的讨论范围,第二点通过 “kmod” 系统解决。

kmod 系统保证了当内核更新后,所有与之安装的模块化驱动程序也得到更新。如果你手动安装一个驱动程序,你就体验不到 kmod 提供的自动化,因此只要能用 kmod 安装包,就应该选择它。例如,尽管英伟达驱动程序以 Nouveau 模块构建在内核中,但官方的驱动程序仅由英伟达发布。你可以去网站上手动安装英伟达旗下的驱动程序,下载 “.run” 文件,并运行提供的 shell 脚本,但在安装了新的内核之后你必须重复相同的过程,因为没有任何东西告诉包管理软件你手动安装了一个内核驱动程序。英伟达驱动着你的显卡,手动更新英伟达驱动程序通常意味着你需要通过终端来执行更新,因为没有显卡驱动程序将无法显示。

 title=

然而,如果你通过 kmod 包安装英伟达驱动程序,更新你的内核也会更新你的英伟达驱动程序。在 Fedora 和相关的发行版中:

$ sudo dnf install kmod-nvidia

在 Debian 和相关发行版上:

$ sudo apt update
$ sudo apt install nvidia-kernel-common nvidia-kernel-dkms nvidia-glx nvidia-xconfig nvidia-settings nvidia-vdpau-driver vdpau-va-driver

这仅仅是一个例子,但是如果你真的要安装英伟达驱动程序,你也必须屏蔽掉 Nouveau 驱动程序。参考你使用发行版的文档获取最佳的步骤吧。

下载并安装驱动程序

不是所有的东西都包含在内核中,也不是所有的东西都可以作为内核模块使用。在某些情况下,你需要下载一个由供应商编写并绑定好的特殊驱动程序,还有一些情况,你有驱动程序,但是没有配置驱动程序的前端界面。

有两个常见的例子是 HP 打印机和 Wacom 数位板。如果你有一台 HP 打印机,你可能有能够和打印机通信的通用的驱动程序,甚至能够打印出东西。但是通用的驱动程序却不能为特定型号的打印机提供定制化的选项,例如双面打印、校对、纸盒选择等等。HPLIP(HP Linux 成像和打印系统)提供了选项来进行任务管理、调整打印设置、选择可用的纸盒等等。

HPLIP 通常包含在包管理软件中;只要搜索“hplip”就行了。

 title=

同样的,电子艺术家主要使用的数位板 Wacom 的驱动程序通常也包含在内核中,但是例如调整压感和按键功能等设置只能通过默认包含在 GNOME 的图形控制面板访问。但也可以作为 KDE 上额外的程序包“kde-config-tablet”来访问。

这里也有几个类似的个别例子,例如内核中没有驱动程序,但是以 RPM 或 DEB 文件提供了可供下载并且通过包管理软件安装的 kmod 版本的驱动程序。

打上补丁并编译你的内核

即使在 21 世纪的未来主义乌托邦里,仍有厂商不够了解开源,没有提供可安装的驱动程序。有时候,一些公司为驱动程序提供开源代码,而需要你下载代码、修补内核、编译并手动安装。

这种发布方式和在 kmod 系统之外安装打包的驱动程序拥有同样的缺点:对内核的更新会破坏驱动程序,因为每次更换新的内核时都必须手动将其重新集成到内核中。

令人高兴的是,这种事情变得少见了,因为 Linux 内核团队在呼吁公司们与他们交流方面做得很好,并且公司们最终接受了开源不会很快消失的事实。但仍有新奇的或高度专业的设备仅提供了内核补丁。

官方上,对于你如何编译内核以使包管理器参与到升级系统如此重要的部分中,发行版有特定的习惯。这里有太多的包管理器,所以无法一一涵盖。举一个例子,当你使用 Fedora 上的工具例如 rpmdevbuild-essential,Debian 上的 devscripts

首先,像通常那样,找到你正在运行内核的版本:

$ uname -r

在大多数情况下,如果你还没有升级过内核那么可以试试升级一下内核。搞定之后,也许你的问题就会在最新发布的内核中解决。如果你尝试后发现不起作用,那么你应该下载正在运行内核的源码。大多数发行版提供了特定的命令来完成这件事,但是手动操作的话,可以在 kernel.org 上找到它的源代码。

你必须下载内核所需的任何补丁。有时候,这些补丁对应具体的内核版本,因此请谨慎选择。

通常,或至少在人们习惯于编译内核的那时,都是拿到源代码并对 /usr/src/linux 打上补丁。

解压内核源码并打上需要的补丁:

$ cd /usr/src/linux
$ bzip2 --decompress linux-5.2.4.tar.bz2
$ cd  linux-5.2.4
$ bzip2 -d ../patch*bz2

补丁文件也许包含如何使用的教程,但通常它们都设计成在内核源码树的顶层可用来执行。

$ patch -p1 < patch*example.patch

当内核代码打上补丁后,你可以继续使用旧的配置来对打了补丁的内核进行配置。

$ make oldconfig

make oldconfig 命令有两个作用:它继承了当前的内核配置,并且允许你配置补丁带来的新的选项。

你或许需要运行 make menuconfig 命令,它启动了一个基于 ncurses 的菜单界面,列出了新的内核所有可能的选项。整个菜单可能看不过来,但是它是以旧的内核配置为基础的,你可以遍历菜单并且禁用掉你没有或不需要的硬件模块。另外,如果你知道自己有一些硬件没有包含在当前的配置中,你可以选择构建它,当作模块或者直接嵌入内核中。理论上,这些并不是必要的,因为你可以猜想,当前的内核运行良好只是缺少了补丁,当使用补丁的时候可能已经激活了所有设备所必要的选项。

下一步,编译内核和它的模块:

$ make bzImage
$ make modules

这会产生一个叫作 vmlinuz 的文件,它是你的可引导内核的压缩版本。保存旧的版本并在 /boot 文件夹下替换为新的。

$ sudo mv /boot/vmlinuz /boot/vmlinuz.nopatch
$ sudo cat arch/x86_64/boot/bzImage > /boot/vmlinuz
$ sudo mv /boot/System.map /boot/System.map.stock
$ sudo cp System.map /boot/System.map

到目前为止,你已经打上了补丁并且编译了内核和它的模块,你安装了内核,但你并没有安装任何模块。那就是最后的步骤:

$ sudo make modules_install

新的内核已经就位,并且它的模块也已经安装。

最后一步是更新你的引导程序,为了让你的计算机在加载 Linux 内核之前知道它的位置。GRUB 引导程序使这一过程变得相当简单:

$ sudo grub2-mkconfig

现实生活中的编译

当然,现在没有人手动执行这些命令。相反的,参考你的发行版,寻找发行版维护人员使用的开发者工具集修改内核的说明。这些工具集可能会创建一个集成所有补丁的可安装软件包,告诉你的包管理器来升级并更新你的引导程序。

内核

操作系统和内核都是玄学,但要理解构成它们的组件并不难。下一次你看到某个技术无法应用在 Linux 上时,深呼吸,调查可用的驱动程序,寻找一条捷径。Linux 比以前简单多了——包括内核。


via: https://opensource.com/article/19/8/linux-kernel-21st-century

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

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

通过 Oh My Zsh 安装的主题和插件来扩展 Zsh 的功能。

在我的前文中,我向大家展示了如何安装并使用 Z-Shell (Zsh)。对于某些用户来说,Zsh 最令人激动的是它可以安装主题。Zsh 安装主题非常容易,一方面是因为有非常活跃的社区为 Z-Shell 设计主题,另一方面是因为有 Oh My Zsh 这个项目。这使得安装主题变得轻而易举。

主题的变化可能会立刻吸引你的注意力,因此如果你安装了 Zsh 并且将默认的 Shell 替换为 Zsh 时,你可能不喜欢 Shell 默认主题的样子,那么你可以立即更换 Oh My Zsh 自带的 100 多个主题。Oh My Zsh 不仅拥有大量精美的主题,同时还有数以百计的扩展 Zsh 功能的插件。

安装 Oh My Zsh

Oh My Zsh 的官网建议你使用一个脚本在有网络的情况下来安装这个包。尽管 Oh My Zsh 项目几乎是可以令人信服的,但是盲目地在你的电脑上运行一个脚本这是一个糟糕的建议。如果你想运行这个脚本,你可以把它下载下来,看一下它实现了什么功能,在你确信你已经了解了它的所作所为之后,你就可以运行它了。

如果你下载了脚本并且阅读了它,你就会发现安装过程仅仅只有三步:

1、克隆 oh-my-zsh

第一步,克隆 oh-my-zsh 库到 ~/.oh-my-zsh 目录:

% git clone http://github.com/robbyrussell/oh-my-zsh ~/.oh-my-zsh

2、切换配置文件

下一步,备份你已有的 .zshrc 文件,然后将 oh-my-zsh 自带的配置文件移动到这个地方。这两步操作可以一步完成,只需要你的 mv 命令支持 -b 这个选项。

% mv -b \
~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

3、编辑配置文件

默认情况下,Oh My Zsh 自带的配置文件是非常简陋的。如果你想将你自己的 ~/.zshrc 文件合并到 .oh-my-zsh 的配置文件中。你可以使用 cat 命令将你的旧的配置文件添加到新文件的末尾。

% cat ~/.zshrc~ >> ~/.zshrc

看一下默认的配置文件以及它提供的一些选项。用你最喜欢的编辑器打开 ~/.zshrc 文件。这个文件有非常良好的注释。这是了解它的一个非常好的方法。

例如,你可以更改 .oh-my-zsh 目录的位置。在安装的时候,它默认是位于你的家目录。但是,根据 Free Desktop 所定义的现代 Linux 规范。这个目录应当放置于 ~/.local/share 。你可以在配置文件中进行修改。如下所示:

# Path to your oh-my-zsh installation.
export ZSH=$HOME/.local/share/oh-my-zsh

然后将 .oh-my-zsh 目录移动到你新配置的目录下:

% mv ~/.oh-my-zsh $HOME/.local/share/oh-my-zsh

如果你使用的是 MacOS,这个目录可能会有点含糊不清,但是最合适的位置可能是在 $HOME/Library/Application\ Support

重新启动 Zsh

编辑配置文件之后,你必须重新启动你的 Shell。在这之前,你必须确定你的任何操作都已正确完成。例如,在你修改了 .oh-my-zsh 目录的路径之后。不要忘记将目录移动到新的位置。如果你不想重新启动你的 Shell。你可以使用 source 命令来使你的配置文件生效。

% source ~/.zshrc
➜  .oh-my-zsh git:(master) ✗

你可以忽略任何丢失更新文件的警告;他们将会在重启的时候再次进行解析。

更换你的主题

安装好 oh-my-zsh 之后。你可以将你的 Zsh 的主题设置为 robbyrussell,这是一个该项目维护者的主题。这个主题的更改是非常小的,仅仅是改变了提示符的颜色。

你可以通过列出 .oh-my-zsh 目录下的所有文件来查看所有安装的主题:

➜  .oh-my-zsh git:(master) ✗ ls ~/.local/share/oh-my-zsh/themes
3den.zsh-theme
adben.zsh-theme
af-magic.zsh-theme
afowler.zsh-theme
agnoster.zsh-theme
[...]

想在切换主题之前查看一下它的样子,你可以查看 Oh My Zsh 的 wiki 页面。要查看更多主题,可以查看 外部主题 wiki 页面。

大部分的主题是非常易于安装和使用的,仅仅需要改变 .zshrc 文件中的配置选项然后重新载入配置文件。

➜ ~ sed -i 's/_THEME=\"robbyrussel\"/_THEME=\"linuxonly\"/g' ~/.zshrc
➜ ~ source ~/.zshrc
seth@darkstar:pts/0-&gt;/home/skenlon (0) ➜

其他的主题可能需要一些额外的配置。例如,为了使用 agnoster 主题,你必须先安装 Powerline 字体。这是一个开源字体,如果你使用 Linux 操作系统的话,这个字体很可能在你的软件库中存在。使用下面的命令安装这个字体:

➜ ~ sudo dnf install powerline-fonts

在配置文件中更改你的主题:

➜ ~ sed -i 's/_THEME=\"linuxonly\"/_THEME=\"agnoster\"/g' ~/.zshrc

重新启动你的 Sehll(一个简单的 source 命令并不会起作用)。一旦重启,你就可以看到新的主题:

 title=

安装插件

Oh My Zsh 有超过 200 的插件,你可以在 .oh-my-zsh/plugins 中看到它们。每一个扩展目录下都有一个 README 文件解释了这个插件的作用。

一些插件相当简单。例如,dnfubuntubrewmacports 插件仅仅是为了简化与 DNF、Apt、Homebres 和 MacPorts 的交互操作而定义的一些别名。

而其他的一些插件则较为复杂,git 插件默认是被激活使用的。当你的目录是一个 git 仓库的时候,这个扩展就会更新你的 Shell 提示符,以显示当前的分支和是否有未合并的更改。

为了激活这个扩展,你可以将这个扩展添加到你的配置文件 ~/.zshrc 中。例如,你可以添加 dnfpass 插件,按照如下的方式更改:

plugins=(git dnf pass)

保存修改,重新启动你的 Shell。

% source ~/.zshrc

这个扩展现在就可以使用了。你可以通过使用 dnf 提供的别名来测试一下:

% dnfs fop
====== Name Exactly Matched: fop ======
fop.noarch : XSL-driven print formatter

不同的插件做不同的事,因此你可以一次安装一两个插件来帮你学习新的特性和功能。

兼容性

一些 Oh My Zsh 插件具有通用性。如果你看到一个插件声称它可以与 Bash 兼容,那么它就可以在你自己的 Bash 中使用。另一些插件需要 Zsh 提供的特定功能。因此,它们并不是所有都能工作。但是你可以添加一些其他的插件,例如 dnfubuntufirewalld,以及其他的一些插件。你可以使用 source 使你的选择生效。例如:

if [ -d $HOME/.local/share/oh-my-zsh/plugins ]; then
        source $HOME/.local/share/oh-my-zsh/plugins/dnf/dnf.plugin.zsh
fi

选择或者不选择 Zsh

Z-shell 的内置功能和它由社区贡献的扩展功能都非常强大。你可以把它当成你的主 Shell 使用,你也可以在你休闲娱乐的时候尝试一下。这取决于你的爱好。

什么是你最喜爱的主题和扩展可以在下方的评论告诉我们!


via: https://opensource.com/article/19/9/adding-plugins-zsh

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

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

  • 更新 2014-05-14:增加了一些具体实例
  • 更新 2015-03-16:根据照片的 GPS 坐标过滤图片
  • 更新 2016-08-29:以新的 filetags --filter 替换已经过时的 show-sel.sh 脚本
  • 更新 2017-08-28: geeqier 视频缩略图的邮件评论
  • 更新 2018-03-06:增加了 Julian Kahnert 的链接
  • 更新 2018-05-06:增加了作者在 2018 Linuxtage Graz 大会上 45 分钟演讲的视频
  • 更新 2018-06-05:关于 metadata 的邮件回复
  • 更新 2018-07-22:移动文件夹结构的解释到一篇它自己的文章中
  • 更新 2019-07-09:关于在文件名中避免使用系谱和字符的邮件回复

每当度假或去哪游玩时我就会化身为一个富有激情的摄影师。所以,过去的几年中我积累了许多的 JPEG 文件。这篇文章中我会介绍我是如何避免 供应商锁定(LCTT 译注: 供应商锁定 vendor lock-in ,原为经济学术语,这里引申为避免过于依赖某一服务平台)造成受限于那些临时性的解决方案及数据丢失。相反,我更倾向于使用那些可以让我投入时间和精力打理,并能长久使用的解决方案。

这一(相当长的)攻略 并不仅仅适用于图像文件:我将进一步阐述像是文件夹结构、文件的命名规则等等许多领域的事情。因此,这些规范适用于我所能接触到的所有类型的文件。

在我开始传授我的方法之前,我们应该先就我将要介绍方法的达成一个共识,那就是我们是否有相同的需求。如果你对 raw 图像格式十分推崇,将照片存储在云端或其他你信赖的地方(对我而言可能不会),那么你可能不会认同这篇文章将要描述的方式了。请根据你的情况来灵活做出选择。

我的需求

对于 将照片(或视频)从我的数码相机中导出到电脑里,我只需要将 SD 卡插到我的电脑里并调用 fetch-workflow 软件。这一步也完成了图像软件的预处理以适用于我的文件命名规范(下文会具体论述),同时也可以将图片旋转至正常的方向(而不是横着)。

这些文件将会被存入到我的摄影收藏文件夹 $HOME/tmp/digicam/。在这一文件夹中我希望能遍历我的图像和视频文件,以便于整理/删除、重命名、添加/移除标签,以及将一系列相关的文件移动到相应的文件夹中

在完成这些以后,我将会浏览包含图像/电影文件集的文件夹。在极少数情况下,我希望在独立的图像处理工具(比如 GIMP)中打开一个图像文件。如果仅是为了旋转 JPEG 文件,我想找到一个快速的方法,不需要图像处理工具,并且是以无损的方式旋转 JPEG 图像。

我的数码相机支持用 GPS 坐标标记图像。因此,我需要一个方法来对单个文件或一组文件可视化 GPS 坐标来显示我走过的路径。

我想拥有的另一个好功能是:假设你在威尼斯度假时拍了几百张照片。每一个都很漂亮,所以你每张都舍不得删除。另一方面,你可能想把一组更少的照片送给家里的朋友。而且,在他们嫉妒的爆炸之前,他们可能只希望看到 20 多张照片。因此,我希望能够定义并显示一组特定的照片子集

就独立性和避免锁定效应而言,我不想使用那种一旦公司停止产品或服务就无法使用的工具。出于同样的原因,由于我是一个注重隐私的人,我不想使用任何基于云的服务。为了让自己对新的可能性保持开放的心态,我不希望只在一个特定的操作系统平台才可行的方案上倾注全部的精力。基本的东西必须在任何平台上可用(查看、导航、……),而全套需求必须可以在 GNU/Linux 上运行,对我而言,我选择 Debian GNU/Linux。

在我传授当前针对上述大量需求的解决方案之前,我必须解释一下我的一般文件夹结构和文件命名约定,我也使用它来命名数码照片。但首先,你必须认清一个重要的事实:

iPhoto、Picasa,诸如此类应被认为是有害的

管理照片集的软件工具确实提供了相当酷的功能。它们提供了一个良好的用户界面,并试图为你提供满足各种需求的舒适的工作流程。

对它们我确实遇到了很多大问题。它们几乎对所有东西都使用专有的存储格式:图像文件、元数据等等。当你打算在几年内换一个不同的软件,这是一个大问题。相信我:总有一天你会因为多种原因而更换软件

如果你现在正打算更换相应的工具,你会意识到 iPhoto 或 Picasa 是分别存储原始图像文件和你对它们所做的所有操作的(旋转图像、向图像文件添加描述/标签、裁剪等等)。如果你不能导出并重新导入到新工具,那么所有的东西都将永远丢失。而无损的进行转换和迁移几乎是不可能的。

我不想在一个会锁住我工作的工具上投入任何精力。我也拒绝把自己绑定在任何专有工具上。我是一个过来人,希望你们吸取我的经验。

这就是我在文件名中保留时间戳、图像描述或标记的原因。文件名是永久性的,除非我手动更改它们。当我把照片备份或复制到 U 盘或其他操作系统时,它们不会丢失。每个人都能读懂。任何未来的系统都能够处理它们。

我的文件命名规范

这里有一个我在 2018 Linuxtage Graz 大会上做的演讲,其中详细阐述了我的在本文中提到的想法和工作流程。

我所有的文件都与一个特定的日期或时间有关,根据所采用的 ISO 8601 规范,我采用的是日期戳时间戳

带有日期戳和两个标签的示例文件名:2014-05-09 Budget export for project 42 -- finance company.csv

带有时间戳(甚至包括可选秒)和两个标签的示例文件名:2014-05-09T22.19.58 Susan presenting her new shoes -- family clothing.jpg

由于我使用的 ISO 时间戳冒号不适用于 Windows NTFS 文件系统,因此,我用点代替冒号,以便将小时与分钟(以及可选的秒)区别开来。

如果是持续的一段日期或时间,我会将两个日期戳或时间戳用两个减号分开:2014-05-09--2014-05-13 Jazz festival Graz -- folder tourism music.pdf

文件名中的时间/日期戳的优点是,除非我手动更改它们,否则它们保持不变。当通过某些不处理这些元数据的软件进行处理时,包含在文件内容本身中的元数据(如 Exif)往往会丢失。此外,使用这样的日期/时间戳开始的文件名可以确保文件按时间顺序显示,而不是按字母顺序显示。字母表是一种完全人工的排序顺序,对于用户定位文件通常不太实用。

当我想将标签关联到文件名时,我将它们放在原始文件名和文件名扩展名之间,中间用空格、两个减号和两端额外的空格分隔 --。我的标签是小写的英文单词,不包含空格或特殊字符。有时,我可能会使用 quantifiedselfusergenerated 这样的连接词。我倾向于选择一般类别,而不是太过具体的描述标签。我在 Twitter hashtags、文件名、文件夹名、书签、诸如此类的博文等诸如此类地地方重用这些标签。

标签作为文件名的一部分有几个优点。通过使用常用的桌面搜索引擎,你可以在标签的帮助下定位文件。文件名称中的标签不会因为复制到不同的存储介质上而丢失。当系统使用与文件名之外的存储位置(如:元数据数据库、点文件备用数据流等)存储元信息通常会发生丢失。

当然,通常在文件和文件夹名称中,请避免使用特殊字符、变音符、冒号等。尤其是在不同操作系统平台之间同步文件时。

我的文件夹名命名约定与文件的相应规范相同。

注意:由于 Memacsfilenametimestamp 模块的聪明之处,所有带有日期/时间戳的文件和文件夹都出现在我的 Org 模式的日历(日程)上的同一天/同一时间。这样,我就能很好地了解当天发生了什么,包括我拍的所有照片。

我的一般文件夹结构

在本节中,我将描述我的主文件夹中最重要的文件夹。注意:这可能在将来的被移动到一个独立的页面。或许不是。让我们等着瞧 :-) (LCTT 译注:后来这一节已被作者扩展并移动到另外一篇文章。)

很多东西只有在一定的时间内才会引起人们的兴趣。这些内容包括快速浏览其内容的下载、解压缩文件以检查包含的文件、一些有趣的小内容等等。对于临时的东西,我有 $HOME/tmp/ 子层次结构。新照片放在 $HOME/tmp/digicam/ 中。我从 CD、DVD 或 USB 记忆棒临时复制的东西放在 $HOME/tmp/fromcd/ 中。每当软件工具需要用户文件夹层次结构中的临时数据时,我就使用 $HOME/tmp/Tools/作为起点。我经常使用的文件夹是 $HOME/tmp/2del/2del 的意思是“随时可以删除”。例如,我所有的浏览器都使用这个文件夹作为默认的下载文件夹。如果我需要在机器上腾出空间,我首先查看这个 2del 文件夹,用于删除内容。

与上面描述的临时文件相比,我当然也想将文件保存更长的时间。这些文件被移动到我的 $HOME/archive/ 子层次结构中。它有几个子文件夹用于备份、我想保留的 web 下载类、我要存档的二进制文件、可移动媒体(CD、DVD、记忆棒、外部硬盘驱动器)的索引文件,和一个稍后(寻找一个合适的的目标文件夹)存档的文件夹。有时,我太忙或没有耐心的时候将文件妥善整理。是的,那就是我,我甚至有一个名为“现在不要烦我”的文件夹。这对你而言是否很怪?:-)

我的归档中最重要的子层次结构是 $HOME/archive/events_memories/ 及其子文件夹 2014/2013/2012/ 等等。正如你可能已经猜到的,每个年份有一个子文件夹。其中每个文件中都有单个文件和文件夹。这些文件是根据我在前一节中描述的文件名约定命名的。文件夹名称以 ISO 8601 日期标签 “YYYY-MM-DD” 开头,后面跟着一个具有描述性的名称,如 $HOME/archive/events_memories/2014/2014-05-08 Business marathon with/。在这些与日期相关的文件夹中,我保存着各种与特定事件相关的文件:照片、(扫描的)pdf 文件、文本文件等等。

对于共享数据,我设置一个 $HOME/share/ 子层次结构。这是我的 Dropbox 文件夹,我用各种各样的方法(比如 unison)来分享数据。我也在我的设备之间共享数据:家里的 Mac Mini、家里的 GNU/Linux 笔记本、Android 手机,root-server(我的个人云),工作用的 Windows 笔记本。我不想在这里详细说明我的同步设置。如果你想了解相关的设置,可以参考另一篇相关的文章。:-)

在我的 $HOME/templates_tags/ 子层次结构中,我保存了各种模板文件LaTeX、脚本、…),插图和徽标,等等。

我的 Org 模式 文件,主要是保存在 $HOME/org/。我练习记忆力,不会解释我有多喜欢 Emacs/Org 模式 以及我从中获益多少。你可能读过或听过我详细描述我用它做的很棒的事情。具体可以在我的博客上查找 我的 Emacs 标签,在 Twitter 上查找 hashtag #orgmode

以上就是我最重要的文件夹子层次结构设置方式。

我的工作流程

哒哒哒,在你了解了我的文件夹结构和文件名约定之后,下面是我当前的工作流程和工具,我使用它们来满足我前面描述的需求。

请注意,你必须知道你在做什么。我这里的示例及文件夹路径和更多只适用我的机器或我的环境你必须采用相应的路径、文件名等来满足你的需求!

工作流程:将文件从 SD 卡移动到笔记本电脑、旋转人像图像,并重命名文件

当我想把数据从我的数码相机移到我的 GNU/Linux 笔记本上时,我拿出它的 mini SD 存储卡,把它放在我的笔记本上。然后它会自动挂载在 /media/digicam 上。

然后,调用 getdigicamdata。它做了如下几件事:它将文件从 SD 卡移动到一个临时文件夹中进行处理。原始文件名会转换为小写字符。所有的人像照片会使用 jhead 旋转。同样使用 jhead,我从 Exif 头的时间戳中生成文件名称中的时间戳。使用 date2name,我也将时间戳添加到电影文件中。处理完所有这些文件后,它们将被移动到新的数码相机文件的目标文件夹: $HOME/tmp/digicam/tmp/

工作流程:文件夹索引、查看、重命名、删除图像文件

为了快速浏览我的图像和电影文件,我喜欢使用 GNU/Linux 上的 geeqie。这是一个相当轻量级的图像浏览器,它具有其他文件浏览器所缺少的一大优势:我可以添加通过键盘快捷方式调用的外部脚本/工具。通过这种方式,我可以通过任意外部命令扩展这个图像浏览器的特性。

基本的图像管理功能是内置在 geeqie:浏览我的文件夹层次结构、以窗口模式或全屏查看图像(快捷键 f)、重命名文件名、删除文件、显示 Exif 元数据(快捷键 Ctrl-e)。

在 OS X 上,我使用 Xee。与 geeqie 不同,它不能通过外部命令进行扩展。不过,基本的浏览、查看和重命名功能也是可用的。

工作流程:添加和删除标签

我创建了一个名为 filetags 的 Python 脚本,用于向单个文件以及一组文件添加和删除标记。

对于数码照片,我使用标签,例如,specialL 用于我认为适合桌面背景的风景图片,specialP 用于我想展示给其他人的人像照片,sel 用于筛选,等等。

使用 geeqie 初始设置 filetags

向 geeqie 添加 filetags 是一个手动步骤:“Edit > Preferences > Configure Editors …”,然后创建一个附加条目 New。在这里,你可以定义一个新的桌面文件,如下所示:

[Desktop Entry]
Name=filetags
GenericName=filetags
Comment=
Exec=/home/vk/src/misc/vk-filetags-interactive-adding-wrapper-with-gnome-terminal.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;

add-tags.desktop

封装脚本 vk-filetags-interactive-adding-wrapper-with-gnome-terminal.sh 是必须的,因为我想要弹出一个新的终端,以便添加标签到我的文件:

#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=85x15+330+5 \
 --tab-with-profile=big \
 --hide-menubar \
 -x /home/vk/src/filetags/filetags.py --interactive "${@}"

#end

vk-filetags-interactive-adding-wrapper-with-gnome-terminal.sh

在 geeqie 中,你可以在 “Edit > Preferences > Preferences … > Keyboard”。我将 tfiletags 命令相关联。

这个 filetags 脚本还能够从单个文件或一组文件中删除标记。它基本上使用与上面相同的方法。唯一的区别是 filetags 脚本额外的 --remove 参数:

[Desktop Entry]
Name=filetags-remove
GenericName=filetags-remove
Comment=
Exec=/home/vk/src/misc/vk-filetags-interactive-removing-wrapper-with-gnome-terminal.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;

remove-tags.desktop

#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=85x15+330+5 \
 --tab-with-profile=big \
 --hide-menubar \
 -x /home/vk/src/filetags/filetags.py --interactive --remove "${@}"

#end

vk-filetags-interactive-removing-wrapper-with-gnome-terminal.sh

为了删除标签,我创建了一个键盘快捷方式 T

在 geeqie 中使用 filetags

当我在 geeqie 文件浏览器中浏览图像文件时,我选择要标记的文件(一到多个)并按 t。然后,一个小窗口弹出,要求我提供一个或多个标签。用回车确认后,这些标签被添加到文件名中。

删除标签也是一样:选择多个文件,按下 T,输入要删除的标签,然后按回车确认。就是这样。几乎没有给文件添加或删除标签的更简单的方法了

工作流程:改进的使用 appendfilename 重命名文件

不使用 appendfilename

重命名一组大型文件可能是一个冗长乏味的过程。对于 2014-04-20T17.09.11_p1100386.jpg 这样的原始文件名,在文件名中添加描述的过程相当烦人。你将按 Ctrl-r (重命名)在 geeqie 中打开文件重命名对话框。默认情况下,原始名称(没有文件扩展名的文件名称)被标记。因此,如果不希望删除/覆盖文件名(但要追加),则必须按下光标键 。然后,光标放在基本名称和扩展名之间。输入你的描述(不要忘记以空格字符开始),并用回车进行确认。

在 geeqie 使中用 appendfilename

使用 appendfilename,我的过程得到了简化,可以获得将文本附加到文件名的最佳用户体验:当我在 geeqie 中按下 a(附加)时,会弹出一个对话框窗口,询问文本。在回车确认后,输入的文本将放置在时间戳和可选标记之间。

例如,当我在 2014-04-20T17.09.11_p1100386.jpg 上按下 a,然后键入Pick-nick in Graz 时,文件名变为 2014-04-20T17.09.11_p1100386 Pick-nick in Graz.jpg。当我再次按下 a 并输入 with Susan 时,文件名变为 2014-04-20T17.09.11_p1100386 Pick-nick in Graz with Susan.jpg。当文件名添加标记时,附加的文本前将附加标记分隔符。

这样,我就不必担心覆盖时间戳或标记。重命名的过程对我来说变得更加有趣!

最好的部分是:当我想要将相同的文本添加到多个选定的文件中时,也可以使用 appendfilename

在 geeqie 中初始设置 appendfilename

添加一个额外的编辑器到 geeqie: “Edit > Preferences > Configure Editors … > New”。然后输入桌面文件定义:

[Desktop Entry]
Name=appendfilename
GenericName=appendfilename
Comment=
Exec=/home/vk/src/misc/vk-appendfilename-interactive-wrapper-with-gnome-terminal.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;

appendfilename.desktop

同样,我也使用了一个封装脚本,它将为我打开一个新的终端:

#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=90x5+330+5 \
 --tab-with-profile=big \
 --hide-menubar \
 -x /home/vk/src/appendfilename/appendfilename.py "${@}"

#end

vk-appendfilename-interactive-wrapper-with-gnome-terminal.sh

工作流程:播放电影文件

在 GNU/Linux 上,我使用 mplayer 回放视频文件。由于 geeqie 本身不播放电影文件,所以我必须创建一个设置,以便在 mplayer 中打开电影文件。

在 geeqie 中初始设置 mplayer

我已经使用 xdg-open 将电影文件扩展名关联到 mplayer。因此,我只需要为 geeqie 创建一个通用的“open”命令,让它使用 xdg-open 打开任何文件及其关联的应用程序。

在 geeqie 中,再次访问 “Edit > Preferences > Configure Editors …” 添加“open”的条目:

[Desktop Entry]
Name=open
GenericName=open
Comment=
Exec=/usr/bin/xdg-open %F
Icon=
Terminal=true
Type=Application
hidden=false
NOMimeType=*;
MimeType=image/*;video/*
Categories=X-Geeqie;

open.desktop

当你也将快捷方式 o (见上文)与 geeqie 关联时,你就能够打开与其关联的应用程序的视频文件(和其他文件)。

使用 xdg-open 打开电影文件(和其他文件)

在上面的设置过程之后,当你的 geeqie 光标位于文件上方时,你只需按下 o 即可。就是如此简洁。

工作流程:在外部图像编辑器中打开

我不太希望能够在 GIMP 中快速编辑图像文件。因此,我添加了一个快捷方式 g,并将其与外部编辑器 “GNU Image Manipulation Program (GIMP)” 关联起来,geeqie 已经默认创建了该外部编辑器。

这样,只需按下 g 就可以在 GIMP 中打开当前图像。

工作流程:移动到存档文件夹

现在我已经在我的文件名中添加了注释,我想将单个文件移动到 $HOME/archive/events_memories/2014/,或者将一组文件移动到这个文件夹中的新文件夹中,如 $HOME/archive/events_memories/2014/2014-05-08 business marathon after show - party

通常的方法是选择一个或多个文件,并用快捷方式 Ctrl-m 将它们移动到文件夹中。

何等繁复无趣之至!

因此,我(再次)编写了一个 Python 脚本,它为我完成了这项工作:move2archive(简写为:m2a),需要一个或多个文件作为命令行参数。然后,出现一个对话框,我可以在其中输入一个可选文件夹名。当我不输入任何东西而是按回车,文件被移动到相应年份的文件夹。当我输入一个类似 Business-Marathon After-Show-Party 的文件夹名称时,第一个图像文件的日期戳被附加到该文件夹($HOME/archive/events_memories/2014/2014-05-08 Business-Marathon After-Show-Party),然后创建该文件夹,并移动文件。

再一次,我在 geeqie 中选择一个或多个文件,按 m(移动),或者只按回车(没有特殊的子文件夹),或者输入一个描述性文本,这是要创建的子文件夹的名称(可选不带日期戳)。

没有一个图像管理工具像我的带有 appendfilename 和 move2archive 的 geeqie 一样可以通过快捷键快速且有趣的完成工作。

在 geeqie 里初始化 m2a 的相关设置

同样,向 geeqie 添加 m2a 是一个手动步骤:“Edit > Preferences > Configure Editors …”,然后创建一个附加条目“New”。在这里,你可以定义一个新的桌面文件,如下所示:

[Desktop Entry]
Name=move2archive
GenericName=move2archive
Comment=Moving one or more files to my archive folder
Exec=/home/vk/src/misc/vk-m2a-interactive-wrapper-with-gnome-terminal.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;

m2a.desktop

封装脚本 vk-m2a-interactive-wrapper-with-gnome-terminal.sh 是必要的,因为我想要弹出一个新的终端窗口,以便我的文件进入我指定的目标文件夹:

#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=157x56+330+5 \
 --tab-with-profile=big \
 --hide-menubar \
 -x /home/vk/src/m2a/m2a.py --pauseonexit "${@}"

#end

vk-m2a-interactive-wrapper-with-gnome-terminal.sh

在 geeqie 中,你可以在 “Edit > Preferences > Preferences … > Keyboard” 将 mm2a 命令相关联。

工作流程:旋转图像(无损)

通常,我的数码相机会自动将人像照片标记为人像照片。然而,在某些特定的情况下(比如从装饰图案上方拍照),我的相机会出错。在那些罕见的情况下,我必须手动修正方向。

你必须知道,JPEG 文件格式是一种有损格式,应该只用于照片,而不是计算机生成的东西,如屏幕截图或图表。以傻瓜方式旋转 JPEG 图像文件通常会解压/可视化图像文件、旋转生成新的图像,然后重新编码结果。这将导致生成的图像比原始图像质量差得多

因此,你应该使用无损方法来旋转 JPEG 图像文件。

再一次,我添加了一个“外部编辑器”到 geeqie:“Edit > Preferences > Configure Editors … > New”。在这里,我添加了两个条目:使用 exiftran,一个用于旋转 270 度(即逆时针旋转 90 度),另一个用于旋转 90 度(顺时针旋转 90 度):

[Desktop Entry]
Version=1.0
Type=Application
Name=Losslessly rotate JPEG image counterclockwise

# call the helper script
TryExec=exiftran
Exec=exiftran -p -2 -i -g %f

# Desktop files that are usable only in Geeqie should be marked like this:
Categories=X-Geeqie;
OnlyShowIn=X-Geeqie;

# Show in menu "Edit/Orientation"
X-Geeqie-Menu-Path=EditMenu/OrientationMenu

MimeType=image/jpeg;

rotate-270.desktop

[Desktop Entry]
Version=1.0
Type=Application
Name=Losslessly rotate JPEG image clockwise

# call the helper script
TryExec=exiftran
Exec=exiftran -p -9 -i -g %f

# Desktop files that are usable only in Geeqie should be marked like this:
Categories=X-Geeqie;
OnlyShowIn=X-Geeqie;

# Show in menu "Edit/Orientation"
X-Geeqie-Menu-Path=EditMenu/OrientationMenu

# It can be made verbose
# X-Geeqie-Verbose=true

MimeType=image/jpeg;

rotate-90.desktop

我创建了 geeqie 快捷键 [(逆时针方向)和 ](顺时针方向)。

工作流程:可视化 GPS 坐标

我的数码相机有一个 GPS 传感器,它在 JPEG 文件的 Exif 元数据中存储当前的地理位置。位置数据以 WGS 84 格式存储,如 47, 58, 26.73; 16, 23, 55.51(纬度;经度)。这一方式可读性较差,我期望:要么是地图,要么是位置名称。因此,我向 geeqie 添加了一些功能,这样我就可以在 OpenStreetMap 上看到单个图像文件的位置: Edit > Preferences > Configure Editors ... > New

[Desktop Entry]
Name=vkphotolocation
GenericName=vkphotolocation
Comment=
Exec=/home/vk/src/misc/vkphotolocation.sh %F
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-gray;image/x-icb;image/x-ico;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-xbitmap;image/x-xpixmap;image/x-pcx;image/svg+xml;image/svg+xml-compressed;image/vnd.wap.wbmp;

photolocation.desktop

这调用了我的名为 vkphotolocation.sh 的封装脚本,它使用 ExifToolMarble 能够读取和可视化的适当格式提取该坐标:

#!/bin/sh

IMAGEFILE="${1}"
IMAGEFILEBASENAME=`basename ${IMAGEFILE}`

COORDINATES=`exiftool -c %.6f "${IMAGEFILE}" | awk '/GPS Position/ { print $4 " " $6 }'`

if [ "x${COORDINATES}" = "x" ]; then
 zenity --info --title="${IMAGEFILEBASENAME}" --text="No GPS-location found in the image file."
else
 /usr/bin/marble --latlon "${COORDINATES}" --distance 0.5
fi

#end

vkphotolocation.sh

映射到键盘快捷键 G,我可以快速地得到单个图像文件的位置的地图定位

当我想将多个 JPEG 图像文件的位置可视化为路径时,我使用 GpsPrune。我无法挖掘出 GpsPrune 将一组文件作为命令行参数的方法。正因为如此,我必须手动启动 GpsPrune,用 “File > Add photos”选择一组文件或一个文件夹。

通过这种方式,我可以为每个 JPEG 位置在 OpenStreetMap 地图上获得一个点(如果配置为这样)。通过单击这样一个点,我可以得到相应图像的详细信息。

如果你恰好在国外拍摄照片,可视化 GPS 位置对在文件名中添加描述大有帮助!

工作流程:根据 GPS 坐标过滤照片

这并非我的工作流程。为了完整起见,我列出该工作流对应工具的特性。我想做的就是从一大堆图片中寻找那些在一定区域内(范围或点 + 距离)的照片。

到目前为止,我只找到了 DigiKam,它能够根据矩形区域进行过滤。如果你知道其他工具,请将其添加到下面的评论或给我写一封电子邮件。

工作流程:显示给定集合的子集

如上面的需求所述,我希望能够对一个文件夹中的文件定义一个子集,以便将这个小集合呈现给其他人。

工作流程非常简单:我向选择的文件添加一个标记(通过 t/filetags)。为此,我使用标记 sel,它是 “selection” 的缩写。在标记了一组文件之后,我可以按下 s,它与一个脚本相关联,该脚本只显示标记为 sel 的文件。

当然,这也适用于任何标签或标签组合。因此,用同样的方法,你可以得到一个适当的概述,你的婚礼上的所有照片都标记着“教堂”和“戒指”。

很棒的功能,不是吗?:-)

初始设置 filetags 以根据标签和 geeqie 过滤

你必须定义一个额外的“外部编辑器”,“ Edit > Preferences > Configure Editors … > New”:

[Desktop Entry]
Name=filetag-filter
GenericName=filetag-filter
Comment=
Exec=/home/vk/src/misc/vk-filetag-filter-wrapper-with-gnome-terminal.sh
Icon=
Terminal=true
Type=Application
Categories=Application;Graphics;
hidden=false
MimeType=image/*;video/*;image/mpo;image/thm
Categories=X-Geeqie;

filter-tags.desktop

再次调用我编写的封装脚本:

#!/bin/sh

/usr/bin/gnome-terminal \
 --geometry=85x15+330+5 \
 --hide-menubar \
 -x /home/vk/src/filetags/filetags.py --filter

#end

vk-filetag-filter-wrapper-with-gnome-terminal.sh

带有参数 --filterfiletags 基本上完成的是:用户被要求输入一个或多个标签。然后,当前文件夹中所有匹配的文件都使用符号链接链接到 $HOME/.filetags_tagfilter/。然后,启动了一个新的 geeqie 实例,显示链接的文件。

在退出这个新的 geeqie 实例之后,你会看到进行选择的旧的 geeqie 实例。

用一个真实的案例来总结

哇哦, 这是一篇很长的博客文章。你可能已经忘了之前的概述。总结一下我在(扩展了标准功能集的) geeqie 中可以做的事情,我有一个很酷的总结:

快捷键功能
m移到归档(m2a)
o打开(针对非图像文件)
a在文件名里添加字段
t文件标签(添加)
T文件标签(删除)
s文件标签(排序)
ggimp
G显示 GPS 信息
[无损的逆时针旋转
]无损的顺时针旋转
Ctrl-eEXIF 图像信息
f全屏显示

文件名(包括它的路径)的部分及我用来操作该部分的相应工具:

 /this/is/a/folder/2014-04-20T17.09 Picknick in Graz -- food graz.jpg
 [ move2archive  ] [  date2name   ] [appendfilename] [ filetags ]

在实践中,我按照以下步骤将照片从相机保存到存档:我将 SD 存储卡放入计算机的 SD 读卡器中。然后我运行 getdigicamdata.sh。完成之后,我在 geeqie 中打开 $HOME/tmp/digicam/tmp/。我浏览了一下照片,把那些不成功的删除了。如果有一个图像的方向错误,我用 [] 纠正它。

在第二步中,我向我认为值得评论的文件添加描述 (a)。每当我想添加标签时,我也这样做:我快速地标记所有应该共享相同标签的文件(Ctrl + 鼠标点击),并使用 filetagst)进行标记。

要合并来自给定事件的文件,我选中相应的文件,将它们移动到年度归档文件夹中的 event-folder,并通过在 move2archivem)中键入事件描述,其余的(非特殊的文件夹)无需声明事件描述由 move2archivem)直接移动到年度归档中。

结束我的工作流程,我删除了 SD 卡上的所有文件,把它从操作系统上弹出,然后把它放回我的数码相机里。

以上。

因为这种工作流程几乎不需要任何开销,所以评论、标记和归档照片不再是一项乏味的工作。

最后

所以,这是一个详细描述我关于照片和电影的工作流程的叙述。你可能已经发现了我可能感兴趣的其他东西。所以请不要犹豫,请使用下面的链接留下评论或电子邮件。

我也希望得到反馈,如果我的工作流程适用于你。并且,如果你已经发布了你的工作流程或者找到了其他人工作流程的描述,也请留下评论!

及时行乐,莫让错误的工具或低效的方法浪费了我们的人生!

其他工具

阅读关于本文中关于 gThumb 的部分

当你觉得你以上文中所叙述的符合你的需求时,请根据相关的建议来选择对应的工具。


via: http://karl-voit.at/managing-digital-photographs/

作者:Karl Voit 译者:qfzy1233 校对:wxy

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

通过命令行获取计算机硬件详细信息。

你可能会有很多的原因需要查清计算机硬件的详细信息。例如,你需要修复某些问题并在论坛上发出请求,人们可能会立即询问你的计算机具体的信息。或者当你想要升级计算机配置时,你需要知道现有的硬件型号和能够升级的型号。这些都需要查询你的计算机具体规格信息。

最简单的方法是使用标准的 Linux GUI 程序之一:

  • i-nex 收集硬件信息,并且类似于 Windows 下流行的 CPU-Z 的显示。
  • HardInfo 显示硬件具体信息,甚至包括一组八个的流行的性能基准程序,你可以用它们评估你的系统性能。
  • KInfoCenterLshw 也能够显示硬件的详细信息,并且可以从许多软件仓库中获取。

或者,你也可以拆开计算机机箱去查看硬盘、内存和其他设备上的标签信息。或者你可以在系统启动时,按下相应的按键进入 UEFI 和 BIOS 界面获得信息。这两种方式都会向你显示硬件信息但省略软件信息。

你也可以使用命令行获取硬件信息。等一下… 这听起来有些困难。为什么你会要这样做?

有时候通过使用一条针对性强的命令可以很轻松的找到特定信息。也可能你没有可用的 GUI 程序或者只是不想安装这样的程序。

使用命令行的主要原因可能是编写脚本。无论你是使用 Linux shell 还是其他编程语言来编写脚本通常都需要使用命令行。

很多检测硬件信息的命令行都需要使用 root 权限。所以要么切换到 root 用户,要么使用 sudo 在普通用户状态下发出命令:

sudo <the_line_command> 

并按提示输入你的密码。

这篇文章介绍了很多用于发现系统信息的有用命令。文章最后的快速查询表对它们作出了总结。

硬件概述

下面几条命令可以全面概述计算机硬件信息。

inxi 命令能够列出包括 CPU、图形、音频、网络、驱动、分区、传感器等详细信息。当论坛里的人尝试帮助其他人解决问题的时候,他们常常询问此命令的输出。这是解决问题的标准诊断程序:

inxi -Fxz

-F 参数意味着你将得到完整的输出,x 增加细节信息,z 参数隐藏像 MAC 和 IP 等私人身份信息。

hwinfolshw 命令以不同的格式显示大量相同的信息:

hwinfo --short

lshw -short

这两条命令的长格式输出非常详细,但也有点难以阅读:

hwinfo

lshw

CPU 详细信息

通过命令你可以了解关于你的 CPU 的任何信息。使用 lscpu 命令或与它相近的 lshw 命令查看 CPU 的详细信息:

lscpu

lshw -C cpu

在这两个例子中,输出的最后几行都列出了所有 CPU 的功能。你可以查看你的处理器是否支持特定的功能。

使用这些命令的时候,你可以通过使用 grep 命令过滤复杂的信息,并缩小所需信息范围。例如,只查看 CPU 品牌和型号:

lshw -C cpu | grep -i product

仅查看 CPU 的速度(兆赫兹):

lscpu | grep -i mhz

或其 BogoMips 额定功率:

lscpu | grep -i bogo

grep 命令的 -i 参数代表搜索结果忽略大小写。

内存

Linux 命令行使你能够收集关于你的计算机内存的所有可能的详细信息。你甚至可以不拆开计算机机箱就能确定是否可以为计算机添加额外的内存条。

使用 dmidecode 命令列出每根内存条和其容量:

dmidecode -t memory | grep -i size

使用以下命令获取系统内存更多的信息,包括类型、容量、速度和电压:

lshw -short -C memory

你肯定想知道的一件事是你的计算机可以安装的最大内存:

dmidecode -t memory | grep -i max

现在检查一下计算机是否有空闲的插槽可以插入额外的内存条。你可以通过使用命令在不打开计算机机箱的情况下就做到:

lshw -short -C memory | grep -i empty

输出为空则意味着所有的插槽都在使用中。

确定你的计算机拥有多少显卡内存需要下面的命令。首先使用 lspci 列出所有设备信息然后过滤出你想要的显卡设备信息:

lspci | grep -i vga

视频控制器的设备号输出信息通常如下:

00:02.0 VGA compatible controller: Intel Corporation 82Q35 Express Integrated Graphics Controller (rev 02)

现在再加上视频设备号重新运行 lspci 命令:

lspci -v -s 00:02.0

输出信息中 prefetchable 那一行显示了系统中的显卡内存大小:

...
Memory at f0100000 (32-bit, non-prefetchable) [size=512K]
I/O ports at 1230 [size=8]
Memory at e0000000 (32-bit, prefetchable) [size=256M]
Memory at f0000000 (32-bit, non-prefetchable) [size=1M]
...

最后使用下面的命令展示当前内存使用量(兆字节):

free -m

这条命令告诉你多少内存是空闲的,多少命令正在使用中以及交换内存的大小和是否正在使用。例如,输出信息如下:

              total        used        free     shared    buff/cache   available
Mem:          11891        1326        8877      212        1687       10077
Swap:          1999           0        1999

top 命令为你提供内存使用更加详细的信息。它显示了当前全部内存和 CPU 使用情况并按照进程 ID、用户 ID 及正在运行的命令细分。同时这条命令也是全屏输出:

top

磁盘文件系统和设备

你可以轻松确定有关磁盘、分区、文件系统和其他设备信息。

显示每个磁盘设备的描述信息:

lshw -short -C disk

通过以下命令获取任何指定的 SATA 磁盘详细信息,例如其型号、序列号以及支持的模式和扇区数量等:

hdparm -i /dev/sda

当然,如果需要的话你应该将 sda 替换成 sdb 或者其他设备号。

要列出所有磁盘及其分区和大小,请使用以下命令:

lsblk

使用以下命令获取更多有关扇区数量、大小、文件系统 ID 和 类型以及分区开始和结束扇区:

fdisk -l

要启动 Linux,你需要确定 GRUB 引导程序的可挂载分区。你可以使用 blkid 命令找到此信息。它列出了每个分区的唯一标识符(UUID)及其文件系统类型(例如 ext3 或 ext4):

blkid

使用以下命令列出已挂载的文件系统和它们的挂载点,以及已用的空间和可用的空间(兆字节为单位):

df -m

最后,你可以列出所有的 USB 和 PCI 总线以及其他设备的详细信息:

lsusb

lspci

网络

Linux 提供大量的网络相关命令,下面只是几个例子。

查看你的网卡硬件详细信息:

lshw -C network

ifconfig 是显示网络接口的传统命令:

ifconfig -a

但是现在很多人们使用:

ip link show

netstat -i

在阅读输出时,了解常见的网络缩写十分有用:

缩写含义
lo回环接口
eth0enp*以太网接口
wlan0无线网接口
ppp0点对点协议接口(由拨号调制解调器、PPTP VPN 连接或者 USB 调制解调器使用)
vboxnet0vmnet*虚拟机网络接口

表中的星号是通配符,代表不同系统的任意字符。

使用以下命令显示默认网关和路由表:

ip route | column -t

netstat -r

软件

让我们以显示最底层软件详细信息的两条命令来结束。例如,如果你想知道是否安装了最新的固件该怎么办?这条命令显示了 UEFI 或 BIOS 的日期和版本:

dmidecode -t bios

内核版本是多少,以及它是 64 位的吗?网络主机名是什么?使用下面的命令查出结果:

uname -a

快速查询表

用途命令
显示所有硬件信息inxi -Fxzhwinfo --shortlshw -short
CPU 信息lscpulshw -C cpu
显示 CPU 功能(例如 PAE、SSE2)`lshw -C cpugrep -i capabilities`
报告 CPU 位数`lshw -C cpugrep -i width`
显示当前内存大小和配置`dmidecode -t memorygrep -i sizelshw -short -C memory`
显示硬件支持的最大内存`dmidecode -t memorygrep -i max`
确定是否有空闲内存插槽`lshw -short -C memorygrep -i empty`(输出为空表示没有可用插槽)
确定显卡内存数量`lspcigrep -i vga 然后指定设备号再次使用;例如:lspci -v -s 00:02.0 显卡内存数量就是 prefetchable` 的值
显示当前内存使用情况free -mtop
列出磁盘驱动器lshw -short -C disk
显示指定磁盘驱动器的详细信息hdparm -i /dev/sda(需要的话替换掉 sda
列出磁盘和分区信息lsblk(简单) 或 fdisk -l(详细)
列出分区 ID(UUID)blkid
列出已挂载文件系统挂载点以及已用和可用空间df -m
列出 USB 设备lsusb
列出 PCI 设备lspci
显示网卡详细信息lshw -C network
显示网络接口ifconfig -aip link shownetstat -i
显示路由表`ip routecolumn -tnetstat -r`
显示 UEFI/BIOS 信息dmidecode -t bios
显示内核版本网络主机名等uname -a

你有喜欢的命令被我忽略掉的吗?请添加评论分享给大家。


via: https://opensource.com/article/19/9/linux-commands-hardware-information

作者:Howard Fosdick 选题:lujun9972 译者:way-ww 校对:wxy

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