ubuntu 备忘录

目录

0. 简介

本文是一个(资深且普通的)Linux 用户的日常使用记录贴。

  • 2012~2014, 使用 fedora, 主要受到 SD 影响
  • 2015~2020, 使用 ubuntu (默认桌面),主要用于深度学习训练环境
  • 2020~2022, 使用 ubuntu + KDE 桌面,主要受 NiHui 影响,用于 C++ 基础库开发
  • 2023~, 重回 Windows, 练习使用不带插件的 Vim, 尝试使用 PowerShell

我认同的 Linux 使用观:

  • 坚持使用,一点一滴进步;
  • 既要会用纯命令行版本的 Linux, 也接纳并会使用桌面版;
  • 桌面版没有优劣区分,只有个人使用经验多少、个人偏好的区分;
  • Linux 桌面也有好用的软件(KolourPaint,Spectacle,Kate)

1. 系统安装后立即做的配置

1.1 换源彻底关闭软件更新提示

用如下 python 脚本生成对应的源, 并拷贝替代 /etc/apt/sources.list 文件:

#!/usr/bin/env python
#coding: utf-8

def get_mirror_site(dist_num_str='16.04', site_name='aliyun'):
    site_mp = {
        'ustc':     'https://mirrors.ustc.edu.cn',
        'aliyun':   'http://mirrors.aliyun.com',
        'tuna':     'https://mirrors.tuna.tsinghua.edu.cn',
        '163':      'http://mirrors.163.com',
        'zju':      'http://mirrors.zju.edu.cn',
        'huawei':   'http://mirrors.huaweicloud.com',
        'lzu':      'http://mirror.lzu.edu.cn',
        'sjtu':     'https://mirrors.sjtug.sjtu.edu.cn'
    }

    site_url = site_mp[site_name]

    dist_mp = {
        '12.04': 'precise',
        '14.04': 'trusty',
        '16.04': 'xenial',
        '16.10': 'yakkety',
        '17.04': 'zesty',
        '17.10': 'artful',
        '18.04': 'bionic',
        '20.04': 'focal',
        '20.10': 'groovy',
        '21.04': 'hirsute',
        '21.10': 'impish',
        '22.04': 'jammy'
    }

    dist_name = dist_mp[dist_num_str]


    mirror_url_lst = [
        '# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释',
        'deb {:s}/ubuntu/ {:s} main restricted universe multiverse'.format(site_url, dist_name),
        '# deb-src {:s}/ubuntu/ {:s} main restricted universe multiverse'.format(site_url, dist_name),
        'deb {:s}/ubuntu/ {:s}-updates main restricted universe multiverse'.format(site_url, dist_name),
        '# deb-src {:s}/ubuntu/ {:s}-updates main restricted universe multiverse'.format(site_url, dist_name),
        'deb {:s}/ubuntu/ {:s}-backports main restricted universe multiverse'.format(site_url, dist_name),
        '# deb-src {:s}/ubuntu/ {:s}-backports main restricted universe multiverse'.format(site_url, dist_name),
        'deb {:s}/ubuntu/ {:s}-security main restricted universe multiverse'.format(site_url, dist_name),
        '# deb-src {:s}/ubuntu/ {:s}-security main restricted universe multiverse'.format(site_url, dist_name),

        '# 预发布软件源,不建议启用',
        '# deb {:s}/ubuntu/ {:s}-proposed main restricted universe multiverse'.format(site_url, dist_name),
        '# deb-src {:s}/ubuntu/ {:s}-proposed main restricted universe multiverse'.format(site_url, dist_name)
    ]
    for mirror_url in mirror_url_lst:
        print(mirror_url)

if __name__ == '__main__':
    # 实际上可以用 vim 编辑 /etc/apt/sources.list, 输入如下命令进行替代:
    # :%s/archive.ubuntu.com/mirrors.huaweicloud.com/g
    get_mirror_site(dist_num_str='22.04', site_name='aliyun')

remember to sudo apt update

1.2 开发相关的基本包

# basic edit, networking, disk
sudo apt install vim curl net-tools

# package management
sudo apt install aptitude apt-file apt-show-versions openssh-server 

## source code version control
sudo apt install git subversion tig

## C/C++ development
sudo apt install autoconf automake libtool gcc g++ clang valgrind cppcheck

## Shell tools
silversearcher-ag zsh tree htop iotop tmux enca ncdu dos2unix

## Python development
sudo apt install python-dev python3-dev

## other stuffs
sudo apt install samba exfat-utils xorg openbox libncurses5-dev

1.3 zsh, oh-my-zsh, josh

sudo apt install zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
sed -i "s/ZSH_THEME=\"robbyrussell\"/ZSH_THEME=\"josh\"/g" ~/.zshrc

默认情况下,oh-my-zsh为基础的zsh,cd进入目录会特别慢,因为oh-my-zsh本身以及使用的theme里的git相关操作很慢,卡顿可能有十几秒。
解决方案:

git config --global --add oh-my-zsh.hide-dirty 1
git config --global --add oh-my-zsh.hide-dirty 1

2. 系统安装以及硬盘相关

2.1 U盘启动ubuntu(安装),进不去桌面

换个usb接口试试。选择try ubuntu而不是install试试。

2.2 启动后提示硬盘出错,进入busybox的initramfs界面

这问题今天(2017-11-21 11:44:35)第一次遇到,解决办法是手动调用磁盘修复命令。虽然它提示了手动修复,但是我怎么知道哪些参数?还是靠百度,靠网友的经历了。
参考http://blog.csdn.net/babyfish13/article/details/51190148,我用的文中第二种方式。

2.3 提示"boot"分区空间不足

是旧的内核太多了。保险的方式是安装byobu后操作。
purge-old-kernels在byobu软件包中,首先,安装byobu:

sudo apt install byobu

运行purge-old-kernels卸载旧内核:

sudo purge-old-kernels

为了保险它会保留最新的两个Linux内核。

参考:[http://blog.topspeedsnail.com/archives/6069](使用purge-old-kernels移除旧的Linux内核-Ubuntu 16.04)

2.4 删除(大)文件后,磁盘可用空间没有变化?

本人把一块3T的硬盘划分出1.1T,挂在/opt了,用来缓解/home和/下捉襟见肘的磁盘空间。
然而,训练产生的caffemodel文件很大,很快,整个/opt也只有70G可用了。尝试查看每个目录占用大小:

cd /opt
du -sh *

找到大块文件后,删掉它,包括用rm命令,和手动右键选择"move to trash"。随后再次du -sh *以及df -Th,发现/opt可用大小还是70G。

问题在于,文件没有真的被干掉,而是被转移在/opt/.Trash/files目录下了。删除这个目录下的文件,就彻底删除了。

2.5 更换硬盘,修复grub启动问题

场景举例:原来是有n块硬盘(n>=2),现在其中某一块坏了,关机状态下把它换下,重新启动机器进ubuntu系统发现黑乎乎一片,进不去系统。

这是因为/etc/fstab文件里的内容和硬盘实际内容不匹配导致的。

解决思路是删掉刚刚取下的硬盘在fstab中的记录(如果有新增硬盘,并且希望系统启动就自动挂载,则也需要配置fstab文件),也就是手动编辑下/etc/fstab内容,去掉不匹配的。

然后记得重装grub:

#----------------------------
# step1: 查看分区,初步认领linux分区
#----------------------------
# 查看磁盘分区情况。比如我有三块硬盘,分别是/dev/sda,/dev/sdb, /dev/sdc,编号按顺序从a到c,
# 我需要搞清楚除了被卸载下来的那块硬盘,现有硬盘分区哪个对应到我先前的Linux分区
# 比如我看到/dev/sdc上各种Linux字样的信息,说明我的原来的Linux装在/dev/sdc上了,等会要挂载到/mnt目录下
sudo fdisk -l

#----------------------------
# step2: 认领各个linux分区
#----------------------------
# 这一步先通过mount -t auto  /dev/sdcX  /mnt 来认领每一个硬盘分区和Linux分区对应关系
# 每次mount一个,然后cd /mnt,看看长什么样子,确认是/啊,还是/home啊,还是/boot啊,甚至/data等
sudo mount -t /dev

#----------------------------
# step3: 挂载/(以及/boot,如果原来有/boot分区)
#----------------------------
# 这一步的目的是确保grub安装的东西是放在原有的Linux分区下的
# 比如我的:
sudo mount /dev/sdc7 /
sudo mount /dev/sdc5 /boot

#----------------------------
# step4: 安装grub
#----------------------------
# 会把grub安装在/mnt/boot目录中
# 也就是原来的Linux系统下的/boot目录
# 为了确保OK,指定一下root-directory,也就是你原来的Linux分区的根目录,并且如果你原来有boot分区那么也要挂载到/分区的/boot目录上
sudo grub-install --root-directory=/mnt/

#----------------------------
# step5: 重启以生效
#----------------------------
sudo reboot

2.6 /etc/fstab的一个潜在错误写法

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda1 during installation
UUID=ddb0b7f0-170b-421e-9311-e2f8915c11d3 /               ext4    errors=remount-ro 0       1
# swap was on /dev/sda5 during installation
UUID=ec109373-8bae-4424-ad3d-367bc0faf1a2 none            swap    sw              0       0

/dev/sdb1     /media/data1      ext4      defaults      1      2
/dev/sdc1     /media/data2      ext4      defaults      1      2
/dev/sdd1     /media/data3      ext4      defaults      1      2
/dev/sde1     /media/data4      ext4      defaults      1      2

如上/etc/fstab内容,其实注释里面已经说的比较清楚了,最好使用blkid命令打印的结果来配置,而不是像贴出来的内容的最后几行那样,第一列用/dev/sdc1这样的写法。

我遇到过的问题是:13服务器上希望增加一块机械盘,增加后无法启动。。。看log和fstab应该有关系。

2.7 挂载磁盘后权限777并且无法修改

很可能是NTFS磁盘。

可以在挂载的时候指定umask,并且要指定ntfs类型、uid、gid

sudo mount /dev/sdb2 ./data2/ -t ntfs -o uid=1000,gid=1000,umask=002

(参考:https://blog.idejie.com/2019/09/24/mount-linux-ntfs-disk/)

update: NTFS盘,挂载时指定-o permission即可正确的在挂载后的磁盘上设定和显示权限:

sudo mount /dev/sdb1 -t ntfs -o permissions /media/Data/

参考: https://wiki.epfl.ch/icit/kb/linux-mount-ntfs-with-permissions

2.8 VMWare 安装 Kubuntu (搭载 KDE Plasma 桌面环境的 ubuntu)

  1. 下载镜像
    https://cdimage.ubuntu.com/kubuntu/releases/20.04.3/release/kubuntu-20.04.3-desktop-amd64.iso

  2. 断网
    第一次安装时没断网, 出现了 KDE 背景,但是前景是空的没有任何窗口、图标或提示文字。
    关闭并删除旧的 ubuntu 虚拟机, 断网, 然后重新安装, 出现了桌面:

  1. 调整窗口大小
    忘记了能否直接调整。直接调整的方法:

若不可选择, 则先安装 vmware tools, 步骤是

  • 先关虚拟机实例
  • 改 CDROM 加载的镜像为 VMWare 安装路径下的 linux.iso
  • 开启虚拟机实例
  • 打开文件夹(dolphin), 找到挂载的 vmware tools 目录并进入
  • 执行目录下的 ./run-updater.sh

然后再从菜单选择 “查看”->"立即适应窗口"

2.9 exfat 无法挂载?

sudo apt-get install exfat-utils

2.10 如何使用 TimeShift 备份和还原 Ubuntu Linux

并没有实践过,只是在知乎的问答下,有网友提到可以用 TimeShift, 来挽救内核升级导致的黑屏等种种问题。
https://linux.cn/article-11619-1.html

3. GPU和显卡驱动相关

3.1 nvidia-smi反应慢

一般出现在4卡以上的机器上。解决办法是输入如下命令:

sudo nvidia-persistenced --persistence-mode

注意:这会开启一个进程(通过ps -ef | grep nvidia查看),如果此时需要重新安装nvidia驱动,尽管已经卸载了同版本驱动,但是新驱动会提示装不上,因为这个persistence的进程没有关掉。kill掉它再重装驱动。

3.2 重启后开机,循环登录

首先是分辨率变的很小,字体很大;并且输入密码后进不了桌面,再次提示输入密码。

这个问题原因比较多,主要参照这篇来分析定位下:https://blog.csdn.net/tangwenbo124/article/details/79120677

我遇到的问题是linux内核更新了,需要装新版nvidia驱动。装nvidia驱动简单,见上面一条经验。但为什么内核版本_不知不觉的_更新了?

  1. /var/log/apt/history.txt显示,今天(重启前)更新了内核:

Start-Data: 2019-03-16 06:45:03
Commandline: /usr/bin/unattended-upgrade
Install: linux-modules-4.4.0-143-generic:amd64 (4.4.0-143.169, automatic), linux-headers-4.4.0-143:amd64(4.4.0-143.169, automatic), linux-heawders-4.4.0-143->generic:amd64(4.4.0-143.169, automatic), linux-modules-extra-4.4.0-143-generic:amd64(4.4.0-143.169, automatic)

然而我并没有手贱地手动更新内核,罪魁祸首其实是unattended-upgrade

man一下发现,这货在每天的cron任务(/etc/cron.daily/apt-compat)重被在随机的时间点触发使用,更新了内核。

对于服务器来说,unattended-upgrade安装了新版安全内核,好像不错;但是对于nvidia驱动(尤其是搞深度学习训练的),如果驱动没配置DKMS那么重启后就循环登录了;即使不使用图形界面,也会遇到问题,只不过问题变成了:NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

禁用unattended-upgrade的方法:

sudo vim /etc/apt/apt.conf.d/10periodic

APT::Periodic::Unattended-Upgrade "0";

3.3 NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

  1. 重启电脑, 在 BIOS 中关闭 secure boot, 然后进入系统看下是否解决。

  2. 若前一步没解决, 则卸载已有驱动,重装合适版本驱动,安装时注意勾选DKMS为yes

  3. 关掉unattended-upgrade(自动更新,会导致内核更新,导致nvidia驱动用不了),已绝后患
    (参考:http://ask.xmodulo.com/disable-automatic-updates-ubuntu.html)

3.4 nvidia 驱动的安装

  1. 在 BIOS 中关闭 secure boot
    否则安装驱动后 nvidia-smi 提示说驱动无法使用。

  2. 使用 apt 命令安装

# 520 版本是 2022-11-06 的最新版。请根据你的需求下载
sudo apt install nvidia-driver-520
  1. 或使用 Software & Updates 软件中心附加驱动进行安装
    感觉本质上仍然是 apt。

  2. 或使用 .run 文件安装

# 禁用 nouveau
sudo vim /etc/modprobe.d/blacklist.conf
blacklist nouveau
options nouveau modeset=0
sudo update-initramfs -u

# 进入 tty 并关闭 DM(display manager)
sudo init 3
DM=`sudo systemctl status display-manager.service | grep 'conf' | cut -d ":" -f2 | cut -d "(" -f1 | cut -d "." -f1`
sudo service $DM stop

# 安装驱动
sudo sh NVIDIA-Linux-x86_64-515.76.run --dkms
  1. 或使用 CUDA 安装包里的
sudo bash ./NVIDIA-CUDA-....run

3.5 卸载 nvidia 驱动

  1. .run 文件安装的,卸载命令
sudo /usr/bin/nvidia-uninstall

或找到原始的.run文件:

sudo bash ./xxx.run --uninstall
  1. cuda安装包里的显卡驱动,卸载命令
sudo /usr/bin/nvidia-uninstall
  1. apt repo 下载安装的:
sudo aptitude search nvidia | grep '^i' #查看
sudo apt remove --purge nvidia-XXX #例如我是nvidia-384

3.6 查看当前使用的显卡驱动

lspci -vnn | grep VGA -A 12 | grep driver

例如我的是Kernel driver in use: nouveau

3.7. cudnn下载慢

需要先登录网页。交给迅雷下载仍然不到200k的速度。
从镜像获取好了:http://file.ppwwyyxx.com/
或者用 https://d.serctl.com/

3.8 cudnn安装

linux下的cudnn安装,可以用如下脚本生成安装所需的shell脚本,适合各种版本的cudnn

#!/bin/sh

"""
Description:
    Generate cudnn installation shell commands via python3 for Linux
Author:
    Zhuo Zhang (imzhuo@foxmail.com)
    2020.08.15 19:00:00 (Asia/Shanghai Time)
Usage:
    Step1: Install cuda first
    Step2: Prepare extracted cudnn (usually named as `cuda` folder)
    Step3: Specify cudnn extract directory and cuda install directory in `__main__` part in this file
    Step4: run `python install-cudnn.py > install-cudnn.sh 2>&1`
    Step5: cat install-cudnn.sh to check if they are correct
    Step6: run that script: `bash ./install-cudnn.sh`
Note:
    You may download cudnn, cuda from my BaiduYun, for academic purpose only!
    link: https://pan.baidu.com/s/1fVE8ekxVMhi5kTtzOapOyw  code: c6ne
"""


import os
import shutil


class CudnnInstaller(object):
    def __init__(self, CUDNN_EXTRACT_DIR, CUDA_INSTALL_DIR):
        """
        CUDNN_EXTRACT_DIR='cuda', CUDA_INSTALL_DIR='/usr/local/cuda-11.0')
        """
        self.CUDNN_EXTRACT_DIR=CUDNN_EXTRACT_DIR
        self.CUDA_INSTALL_DIR=CUDA_INSTALL_DIR


    def get_install_commands(self):
        cmd_lst1 = self.copy_header_files()
        cmd_lst2 = self.copy_library_files()
        cmd_lst = cmd_lst1 + cmd_lst2
        return cmd_lst


    def copy_header_files(self):
        src_include_dir = os.path.join(self.CUDNN_EXTRACT_DIR, 'include')
        dst_include_dir = os.path.join(self.CUDA_INSTALL_DIR, 'include')
        cmd_lst = []
        for item in os.listdir(src_include_dir):
            src_pth = os.path.join(src_include_dir, item)
            dst_pth = os.path.join(dst_include_dir, item)
            cmd_lst.append('sudo cp {:s} {:s}'.format(src_pth, dst_pth))
        return cmd_lst


    def copy_library_files(self):
        src_lib_dir = os.path.join(self.CUDNN_EXTRACT_DIR, 'lib64')
        dst_lib_dir = os.path.join(self.CUDA_INSTALL_DIR, 'lib64')
        cmd_lst = []

        g_version_major = None
        g_version_whole = None
        valid = True
        shared_libs = []

        for item in os.listdir(src_lib_dir):
            if item.endswith('_static.a'):
                src_pth = os.path.join(src_lib_dir, item)
                dst_pth = os.path.join(dst_lib_dir, item)
                cmd_lst.append('sudo cp {:s} {:s}'.format(src_pth, dst_pth))
            elif '.so' in item:
                stuffs = item.split('.')
                head = stuffs[0]

                if(len(stuffs)==2):
                    shared_libs.append(item)

                elif(len(stuffs)==3):
                    version_major = stuffs[2]
                    if(g_version_major is None):
                        g_version_major = version_major
                    elif version_major!=version_major:
                        valid = False
                        print('Error! version major not valid...')
                        break

                elif(len(stuffs)==5):
                    version_whole = '.'.join(stuffs[2:])
                    if (g_version_whole is None):
                        g_version_whole = version_whole
                    elif (version_whole!=version_whole):
                        valid = False
                        print('Error! version whole not valid...')
                        break

        if(valid is False):
            return []

        #print('g_version_whole is', g_version_whole)
        #print('g_version_major is', g_version_major)

        for lib_name in shared_libs:
            lib_name_whole = lib_name + '.' + g_version_whole
            src_lib_pth = os.path.join(src_lib_dir, lib_name_whole)
            dst_lib_pth = os.path.join(dst_lib_dir, lib_name_whole)
            cmd = 'sudo cp {:s} {:s}'.format(src_lib_pth, dst_lib_pth)
            cmd_lst.append(cmd)

            cmd = 'sudo ln -sf {:s}/{:s}.{:s} {:s}/{:s}.{:s}'.format(
                dst_lib_dir, lib_name, g_version_whole,
                dst_lib_dir, lib_name, g_version_major
            )
            cmd_lst.append(cmd)

            cmd = 'sudo ln -sf {:s}/{:s}.{:s} {:s}/{:s}'.format(
                dst_lib_dir, lib_name, g_version_major,
                dst_lib_dir, lib_name
            )
            cmd_lst.append(cmd)

        return cmd_lst


if __name__ == '__main__':

    CUDNN_EXTRACT_DIR='cuda'
    CUDA_INSTALL_DIR='/usr/local/cuda-11.0'

    inst = CudnnInstaller(CUDNN_EXTRACT_DIR, CUDA_INSTALL_DIR)
    cmd_lst = inst.get_install_commands()

    print('#!/bin/sh')
    print('set -e')
    print('set -x')
    for cmd in cmd_lst:
        print(cmd)

3.9 nvidia显卡驱动需要重装

应该是安装nvidia显卡驱动的时候没有打到内核里面去。。。还没有测试过,不过看起来应该是这么搞的:

https://askubuntu.com/questions/841876/how-to-disable-nouveau-kernel-driver

参考其中第二个答案,主要是dkms的安装、重新编译内核、重启

3.10 Failed to initialize NVML: Driver/library version mismatch.

我遇到这个问题的场景:先前用的cuda9.0,以及nvidia驱动是384(还是396?不太确定,反正低于400);然后新装了cuda10,因为cuda10必须要nvidia驱动>=410才可以正常用。

(update 2024.02.01: 有同事遇到同样的报错,尝试重启电脑,发现在登录界面输入密码后黑屏;可以ssh登录,并且此时 nvidia-smi 结果已经正常了; 他使用了两个显示器,并且都是插在独立显卡上;改为使用集成显卡插槽上连线后,可以正常进入桌面了)

解决办法:先卸载(如果有)原有nvidia驱动,然后安装合适版本的新驱动:
1) 卸载:

sudo apt install aptitude
sudo aptitude search nvidia | grep '^i'
sudo apt remove --purge nvidia-XXX #例如我是nvidia-384

2)从nvidia官方根据自己机器显卡型号和操作系统,下载对应的驱动。我下载了418版本的。

  1. 安装
sudo init 3
sudo chmod +x NVIDIA-Linux-x86_64-418.43.run
sudo ./NVIDIA-Linux-x86_64-418.43.run

安装过程中注意看提示,不要一股脑全都选默认的。比如我安装时候提示说什么“pre-install脚本失败”,其实继续安装并没有问题;还有就是DKMS要选择yes,用来确保下次更新了内核时自动注册nvidia驱动模块到内核中

参考:https://comzyh.com/blog/archives/967/

3.11 使用阿里云的CUDA源

首先从nvdia官方下载cuda的network包,安装。
安装好了之后,估计是/etc/apt/sources.list.d/目录下有个对应的配置文件,把里面的nvidia那边的repo地址改成阿里云的nvidia-cuda的repo地址即可:

说明:这个方法有时候不能添加key导致无法下载;有时候需要同时配置aliyun和官方nvidia的repo否则aliyun提供的下载不完整导致下载失败。

3.12 本地显示远程绘图

原理是通过ssh的X11转发来做到,本地客户端的话根据操作系统不同,用的接收X11转发的工具也不一样。

windows的话用Ximg+putty,参考 https://www.jianshu.com/p/8a612eb239b7

4. 网络相关

4.1 ssh突然无法连接

比如A想ssh到B但是连不上。首先确认B开启了sshd服务,并且如果有错误的话,也能在查看服务的时候看到:

sudo service ssdh status

发生过的实际例子是,B上的shell先前用的zsh,后来删掉了换成了bash,然后A这里,先前能连B,后来连不上。简单办法是B上装上zsh即可。

4.2 明确 /etc/environment的存在

2018-12-25 20:58:50
今天晚上帮同事配hexo,这个开源博客系统很久之前玩过,基于nodejs的,npm包的下载通常是卡脖子的问题,今天也是卡在这里。
具体描述:已经配置了npm镜像,无论是否开启代理(to cross the great wall),都无法下载hexo,一直提示localhost的1080端口走不通。

我的思路:肯定是某个配置文件设定了1080代理端口,直觉是~/.bashrc或者/etc/profile设定的,这俩文件应该说是进入bash后必然执行的两个文件了。然而naive,就算不加载这两个文件,环境变量$http_proxy依然是1080。

最后总算找到,是/etc/environment这个文件设定了1080代理。

/etc/environment设定了系统级别的环境变量。没什么特殊癖好的话别在这个文件里写东西,这是StackOverFlow上的网友以及我的共同观点。因为修改它导致的环境变量出问题,大部分人根本不知道这玩意儿的存在。。

4.3 git clone被限速怎么办

用ping命令查询域名 github.global.ssl.fastly.net 公网地址并添加到hosts文件。

windows修改host文件: C:\Windows\System32\drivers\etc\hosts
linux 修改host文件: /etc/hosts

e.g.

151.101.41.194 github.global.ssl.fastly.net  

4.4 ifconfig命令没找到?

sudo apt install net-tools

5. 内存相关

5.1 清理 swap 内存

例如 VSCode、浏览器等,开了很多实例,16G内存仍然接近用完;恰好又开启一个 Ninja 编译(默认多线程),很容易导致卡死。
解决方法是,先关掉一些不用的 VSCode 和 浏览器实例, 然后把 swap 内存的东西倒回内存:

sudo swapoff -a; sudo swapon -a

5.2 清理系统内存

free -h 得到的内存统计量:

  • free: 物理内存中空闲的
  • buff/cache: 缓冲和缓存的,通常是I/O操作较多,导致OS把内存拿去当buff/cache用,包括正在用的、用完了但是没有去清理的
  • available: 进程认为可以用的内存,也就是free+buff/cache
  • swap: 根据swapiness值,例如ubuntu默认为60,当free不足40%时,会使用swap

由于 buff/cache 似乎不会自动清空,重启系统又没有必要,考虑手动清理:

# ubuntu20.04亲测有效
sudo sysctl -w vm.drop_caches=3

# 或:
# 我这里ubuntu20.04无效
sudo sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

然后把swap上的也搬运回来

sudo swapoff -a; sudo swapon -a

6. C/C++开发相关

6.1 查看库文件(libxxx.a/libxxx.so,动态静态库均可)是哪个编译器生成的

objdump -s --section=.comment libxxx.a    #静态库

objdump -s --section=.comment libxxx.so  #动态库

6.2 ldd查看动态库的依赖项

ldd libxxx.so

通常可以查看出glibc版本,确定gcc版本

6.3 protobuf报错,未定义的引用

可能出现在很多软件的编译环节。比如,编译opencv的时候,编译了opencv contrib中的dnn模块,该模块需要用protobuf来转换Caffe的模型。报错如下:

[ 75%] Linking CXX executable ../../bin/opencv_test_dnn
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(int, std::string const&, google::protobuf::io::CodedOutputStream*)’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::io::CodedOutputStream::WriteStringWithSizeToArray(std::string const&, unsigned char*)’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::internal::WireFormatLite::ReadString(google::protobuf::io::CodedInputStream*, std::string*)’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::Message::GetTypeName() const’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::internal::StringTypeHandlerBase::Delete(std::string*)’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::MessageFactory::InternalRegisterGeneratedFile(char const*, void (*)(std::string const&))’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(int, std::string const&, google::protobuf::io::CodedOutputStream*)’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::internal::StringTypeHandlerBase::New()’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::internal::empty_string_’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::internal::WireFormatLite::WriteString(int, std::string const&, google::protobuf::io::CodedOutputStream*)’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::DescriptorPool::FindFileByName(std::string const&) const’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::internal::WireFormatLite::ReadBytes(google::protobuf::io::CodedInputStream*, std::string*)’未定义的引用
../../lib/libopencv_dnn.so.3.1.0:对‘google::protobuf::Message::InitializationErrorString() const’未定义的引用
collect2: error: ld returned 1 exit status
modules/dnn/CMakeFiles/opencv_test_dnn.dir/build.make:258: recipe for target 'bin/opencv_test_dnn' failed
make[2]: *** [bin/opencv_test_dnn] Error 1
CMakeFiles/Makefile2:4958: recipe for target 'modules/dnn/CMakeFiles/opencv_test_dnn.dir/all' failed
make[1]: *** [modules/dnn/CMakeFiles/opencv_test_dnn.dir/all] Error 2

解决办法:一开始我猜是存在多个版本的protobuf导致的。其实这个思维定式在一定条件下是正确的。然而本质原因是:你的protobuf对应的动态链接库文件(protobuf-xxx-.so),它被编译出来的时候的g++版本,和你当前使用的(比如用来编译OpenCV的dnn模块)的g++版本不一致。

典型的例子:因为一些原因,切换了g++版本。个人是很讨厌切换系统g++版本的,会导致类似这个例子中的各种问题。要用不同版本的g++,可以,但是不要替换系统默认的g++。

6.4 编译链接报错说缺少.so文件,查找和安装对应的apt包

举例:编译安装了 clang后,编译darknet的第一次commit的源码,提示说LLVMgold.so找不到。则利用apt-file查找该.so文件对应的apt包的名字,然后apt安装:

sudo apt-file update
apt-file search LLVMgold.so

6.5 64位ubuntu编译32位程序

默认不支持32位编译,例如:

(base) zz@localhost:~/work/test$  g++ -std=c++11 -mavx -m32 main2.cpp
In file included from main2.cpp:5:0:
/usr/include/c++/5/iostream:38:28: fatal error: bits/c++config.h: No such file or directory

第一步:确认64为架构的内核

dpkg --print-architecture

输出:
adm64

第二步:确认打开了多架构支持功能

dpkg --print-foreign-architectures

输出:
i386

说明已打开,如果没有需要手动打开

打开多架构支持

sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get dist-upgrade

如此这般你就拥有了64位系统对32位的支持

最后是安装 multilab

sudo apt-get install build-essential gcc-multilib g++-multilib # 经测试发现和gcc-arm-gnueabihf, g++-arm-gnueabihf冲突

#如下的安装方式会更加合理,可以和gcc/g++的gnueabihf编译器共存
sudo apt install libc6:i386 libstdc++6:i386
sudo apt install lib32ncurses5 lib32z1

解决:

sudo apt install lib32z1

不知道lib32z1是否会引发别的冲突。

还有一种方法(暂时没有试过),在project()之前,设定:

set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")

(via: https://stackoverflow.com/a/53635241/2999096)

P.S. 对应的toolchain我放在 https://github.com/zchrissirhcz/cmake_examples 这个repo里了

6.6 cmake用arm-linux-gnueabihf-gcc交叉编译失败

用的是 linaro 官网手动下载的 gcc-linaro-arm-linux-gnueabihf-4.8 ,而不是apt装的。(apt装的直接没有问题)。

  The C compiler

    "/home/zz/soft/gcc-linaro-arm-linux-gnueabihf-4.8/bin/arm-linux-gnueabihf-gcc"

  is not able to compile a simple test program.

  It fails with the following output:

关键一句:

error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory

6.7 Linux gdbserver+gdb 调试

Linux gdbserver+gdb 调试

6.8. pkg-config 的使用

命令行用法: opencv4 的例子

// use_opencv.cpp
#include <opencv2/opencv.hpp>
int main() { cv::Mat mat(2, 3, CV_8UC1); return 0; }
# 确定.pc文件路径
dpkg -L libopencv-dev | grep '.pc$' | xargs realpath | xargs dirname
# 得到 /usr/lib/x86_64-linux-gnu/pkgconfig/opencv4.pc , 则后续用 opencv4 而不是 opencv

# 设置优先查找.pc文件的路径
export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig

# 执行原生编译命令的编译
g++ -o a.out use_opencv.cpp `pkg-config --cflags --libs opencv4`

在 makefile 中的用法

https://github.com/XingangPan/seg_label_generate/blob/master/Makefile

本质上和 pkg-config 原生用法一样。

cmake 和 pkg-config 结合使用

在cmake中使用pkg-config

6.9 ubuntu 20.04 安装 clang-14 和 lldb-14

2021年12月08日09:04:07

按 llvm 官方 apt 源安装

wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 14

修复 python 环境 import lldb 失败问题

sudo apt remove clang-10 lldb-10
sudo apt install lldb-14 clangd-14 clangd
cd /usr/lib/llvm-14/lib
sudo ln -sf ../../x86_64-linux-gnu/liblldb-14.so ./liblldb.so
export PYTHONPATH=/usr/lib/llvm-14/lib/python3.8/site-packages

VSCode 改配置用于替换 CodeLLDB 自带的 lldb 动态库

settings.json

    "lldb.library": "/usr/lib/llvm-14/lib/liblldb.so.1",
    "lldb.adapterEnv": {"LLDB_DEBUGSERVER_PATH": "/usr/lib/llvm-14/bin/lldb-server-14.0.0"}

7. Python 相关

7.1 设定 PYTHONPATH

先前一直以为PYTHONPATH用来找第三方module的。对,但是不完全。
设定PYTHONPATH为分隔符(win下为分号,Linux下为冒号)开头或结尾,则运行阶段sys.path中,sys.path[1]会是“执行当前脚本时所在的目录”。
例如运行一个开源项目,目录结构:

  • tools/test.py
  • utils/stat.py
    要执行tools/test.py,并且里面会import utils.stat模块,则因为设定了PYTHONPATH,使得test.py目录和项目根目录都在sys.path中,能够自然的包含utils目录而不是报错。

7.2 ~/.pip/pip.conf不生效

根据 pip官方文档,最新的pip默认用~/.config/pip/pip.conf来加载配置项。

实测,如果~/.config/pip/pip.conf有配置源,则~/.pip/pip.conf不生效。

7.3 安装python3.6

项目用到python3.6特性(比如f'name.png'形式的表达)。ubuntu16.04默认的python3是3.5。

以下做法搜集自网络,表面上看起来可用,但是隐患众多。最简单的例子:重启后gnome-terminal可能用不了了。因为很多系统工具比如gnome-terminal用了python3.5,如果把系统的python3从python3.5改到python3.6会埋藏各种隐患。最好是自行编译,对于项目中需要用python3.6的地方,通过#!/usr/bin/env python3.6来指定

(update@2021-12-08 09:09:52 应当用 Miniconda / Anaconda 而不是自行换系统的 Python)

添加ppa源并安装

sudo add-apt-repository ppa:jonathonf/python-3.6
sudo apt update
sudo apt install python3.6
sudo apt install python3.6-dev #!这里是重点!记得装dev包,不然后续pip3 install xx时容易报错提示Python.h找不到

设定python3默认指向python3.6:

sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5  1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6  2

确认一下:

python3  -V

补救措施
如果你不幸重启后发现gnome-terminal不能用了。执行这些:

sudo apt-get remove --purge python-apt 
sudo apt-get install python-apt -f  
cd /usr/lib/python3/dist-packages/ 
sudo ln -sf apt_pkg.cpython-35m-x86_64-linux-gnu.so apt_pkg.cpython-36m-x86_64-linux-gnu.so

cd /usr/lib/python3/dist-packages/gi
sudo ln -sf _gi.cpython-35m-x86_64-linux-gnu.so _gi.cpython-36m-x86_64-linux-gnu.so
sudo ln -sf _gi_cairo.cpython-35m-x86_64-linux-gnu.so _gi_cairo.cpython-36m-x86_64-linux-gnu.so

# 以下两个如果没有执行,则software & updates的GUI程序窗口就打不开了。
sudo ln -sf _dbus_glib_bindings.cpython-35m-x86_64-linux-gnu.so _dbus_glib_bindings.cpython-36m-x86_64-linux-gnu.so
sudo ln -sf _dbus_bindings.cpython-35m-x86_64-linux-gnu.so _dbus_bindings.cpython-36m-x86_64-linux-gnu.so

ref1, ref2

7.4 不要用man pip3

在用pip3装python包,并且开了lantern的socks代理。但是还是提示socks错误,很奇怪。
然想让pip缓存文件。于是man pip3。没想到里面的帮助信息都是过时的。

正确方法是:pip3 --help而不是man pip3

7.5 Python 环境

建议使用 conda 系列安装包,避免由于系统自带 python 版本无法升级或版本不满足需求导致的问题

  • miniconda
  • anaconda
  • conda forge

若坚持用 apt 里的 python, 则使用如下命令:

mkdir -p ~/.pip
(
cat << EOF
[global]
index-url = https://pypi.doubanio.com/simple
EOF
) > ~/.pip/pip.conf

sudo apt install -y python-pip
sudo pip install -U pip
sudo apt remove -y python-pip

sudo apt  install -y python3-pip
sudo pip3 install  -U  pip
sudo apt remove -y python3-pip

sudo sed -i "s/\/usr\/bin\/python3/\/usr\/bin\/python/g" `which pip`

7.6 正确安装pip, pip3

需要安装pip,并且pip升级到最新版。现在(2018.07.28)可行的做法(亲测有效,ubuntu16.04):

sudo  apt  install  python-pip    #用apt装pip,是8.0版的pip
sudo  pip  install  -U  pip           #用8.0的pip给自己升级
sudo  apt  remove  python-pip  #干掉apt装的(老版本的)pip.  现在,系统有的pip,是最新版的pip

pip3?如法炮制:

sudo  apt  install  python3-pip
sudo  pip3  install  -U  pip
sudo  apt  remove  python-pip

sudo  vim   `which  pip`   #查看一下pip,是否被python3给覆盖了,也就是确保解释器为#!/usr/bin/python而不是#!/usr/bin/python3

8. Android 相关

8.1 配置android相关环境

最近突然觉得各种rc文件很方便,需要用的时候source一下就能用,不需要的时候也不至于污染系统PATH,哈哈。
~/.androidrc内容:

export ANDROID_SDK=/home/zz/Android/Sdk                                          
export PATH=$ANDROID_SDK/cmake/3.6.4111459/bin:$ANDROID_SDK/platform-tools:$PATH 
export ANDROID_NDK=/home/zz/Android/Sdk/ndk-bundle                               

使用android ndk构建之前,只需要source ~/.androidrc再cmake构建即可。

8.2 android-studio

真机调试:需要先设定udev的规则。
参考:http://www.jianshu.com/p/958361328ae5

9. CMake 相关

9.1 cmake项目的编译脚本

cmake执行后产生log,希望保存log方便后续查看。
cmake可能有很多参数,一下子记不住。
那么使用这个脚本:

#!/bin/bash
# compile.sh
set -x   #把本行后的脚本执行内容,打印到屏幕。用于调试
set -e   #本行后,如果某行执行结果返回值不是true,那么终止

LOG="log.build"
touch $LOG
rm $LOG

exec &> >(tee -a "$LOG")   #将屏幕输出内容,同时写入log文件:便于后续查找

echo "Logging to $LOG"


BUILD_ROOT=build
if [ -d $BUILD_ROOT ]; then
    rm -rf $BUILD_ROOT
fi
mkdir -p $BUILD_ROOT
cd $BUILD_ROOT
echo "building root folder is $BUILD_ROOT"

echo "Now do cmake"

cmake ..

echo "Now do make"

make -j8

echo "Done"

在此基础上可以添加sudo make install,以及cmake的各种option值。

9.2 使用外部库的CMakeLists.txt

dlib

比如使用dlib库写自己的代码。那么自行下载并编译dlib,会同时生成静态库libdlib.a和动态库libdlib.dylib文件。

要使用dlib(静态库、动态库都可以),假设我的代码只有一个assignment_learning_ex.cpp文件(来自dlib的tutorial),那么它配套的CMakeLists.txt这样写:

cmake_minimum_required(VERSION 2.8.12)

project(examples)

set (CMAKE_CXX_STANDARD 11)  # -std=c++11

set(INC_DIR /Users/tusdk/work/dlib)   #dlib头文件路径,改成你的

set(LINK_DIR /Users/tusdk/work/dlib/build/dlib)  #dlib库文件路径,改成你的

include_directories(${INC_DIR})

link_directories(${LINK_DIR})

add_executable(assignment_learning_ex assignment_learning_ex.cpp)

target_link_libraries(assignment_learning_ex dlib)

.cpp文件和CMakeLists.txt文件放同一目录下,执行:

mkdir -p build
cd build
cmake ..
make -j8

完成编译,可以运行了。

这种写法,应该是比较方便使用的,每次只编译自己代码就好了,dlib不用重新编译。

而dlib官方的文档,意思是自己的调用dlib库的程序(用cmake构建),每次都重新编译dlib。虽然说了一堆道理,但是编译dlib对我来说没有必要,浪费时间,不如去掉,所以,用我贴出来这个脚本会方便。

在cmake项目中使用自行编译的opencv

find_package时指定opencv编译的build目录即可。其实前面的dlib,原则上这么做应该也行。但是dlib生成的.cmake脚本不在同一目录有点麻烦。

caffe2中有个Dependencies.cmake,稍作修改,把opencv的部分拿出来:

# ---[ OpenCV
if(USE_OPENCV)
  # OpenCV 3
  find_package(OpenCV QUIET COMPONENTS core highgui imgproc imgcodecs
      CONFIG
      PATHS "/Users/tusdk/work/opencv/build/")
  if(NOT OpenCV_FOUND)
    # OpenCV 2
    find_package(OpenCV QUIET COMPONENTS core highgui imgproc)
  endif()
  if (OpenCV_FOUND)
    include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS})
    list(APPEND Caffe2_DEPENDENCY_LIBS ${OpenCV_LIBS})
    message(STATUS "OpenCV found (${OpenCV_CONFIG_PATH})")
  else()
    message(WARNING "Not compiling with OpenCV. Suppress this warning with -DUSE_OPENCV=OFF")
    set(USE_OPENCV OFF)
  endif()
endif()

==== update =====

也是被opencv和cmake折腾的醉了。仔细看了下cmake的find_package的文档后,才知道怎么master这些包(比如opencv)

对于自行编译的opencv 假设安装在了/opt/opencv-git-master 那么通过在CMakeLists.txt里设定CMAKE_PREFIX_PATH,能最高优先级地设定opencv的查找路径。e.g.:

cmake_minimum_required(VERSION 3.2)
project(play)

message("CMAKE_MODULE_PATH is: ${CMAKE_MODULE_PATH}")
message("CMAKE_SYSTEM_PREFIX_PATH: ${CMAKE_SYSTEM_PREFIX_PATH}")
message("CMAKE_SYSTEM_FRAMEWORK_PATH: ${CMAKE_SYSTEM_FRAMEWORK_PATH}")
message("CMAKE_SYSTEM_APPBUNDLE_PATH: ${CMAKE_SYSTEM_APPBUNDLE_PATH}")

list(APPEND CMAKE_PREFIX_PATH "/opt/opencv-git-master")  ##!! 这里在设定
# 假如是apt装的opencv,那么先通过dpkg -L libopencv-dev查询知道,.cmake文件在/usr/share/OpenCV,那么用下面这行:
#list(APPEND CMAKE_PREFIX_PATH "/usr/share/OpenCV/")
message("CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}")

find_package(OpenCV
    #NO_CMAKE_PATH
    #NO_CMAKE_ENVIRONMENT_PATH
    #NO_SYSTEM_ENVIRONMENT_PATH
    #NO_CMAKE_PACKAGE_REGISTRY
    #NO_CMAKE_SYSTEM_PATH
    )

message(${OpenCV_DIR})

#add_executable(hello main.cpp)

而如果你opencv安装在/usr/local或者/usr/local/opencv开头的路径中,那么不用设定CMAKE_PREFIX_PATH就能被找到,当然设定这个变量会有更高优先级。

具体参考cmake官方文档中find_package()的内容,或者cmake简明使用指南.

10. shell 和命令行工具的使用

10.1 只列出当前目录下文件/目录

只列出当前目录下的文件:经典做法是 ls+grep正则:

ls -al | grep '^[^d]'

不过还可以不记正则,用find:

find . -maxdepth 1 -type f

类似的,只列出当前目录下的目录(只考虑一层),两种写法分别是:

ls -al | grep '^d'
find . -maxdepth 1 -type d

10.2 shell 中的 "-o -" 是什么作用?

-o 意思是指定输出, 后面通常是跟着一个文件名字。
- 则表示 stdout。

举例

echo "int main() { return 0;}" >> main.c
gcc main.c -S -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm -o -

10.3 好用的命令与参数搭配

将所有文件的文件内容的编码,转换为UTF-8

find . ! -type d -exec enca -L zh_CN -x UTF-8 {} \;

将所有 .h.cpp 文件内容的编码, 转为 UTF-8 (使用 -name 搭配 -or 来匹配多个模式):

find . -type f -name '*.h' -or -name '*.cpp' -exec enca -L zh_CN -x UTF-8 {} \;

将所有c/cpp/h文件的行尾换行符,从unix改成dos(使用场景:工程的代码中有//开头的中文注释,在linux下可正常编译,在visual studio中编译报错,报错地点处于"//开头的注释后的一行"对应的字段/变量定义等):

find . -name '*.[c|cpp|h]' -exec unix2dos {} \;

将当前目录下所有 .c 文件拷贝到 dog 目录下:

find ./ -name "*.c" -exec cp '{}' ./dog/ \;

将指定目录下所有文件权限设定为644

find . ! -type d -exec chmod 644 {} \;

将指定目录下所有目录权限设定为755

find .  -type d -exec chmod 755 {} \;

替换文本文件中行尾换行符,从dos(CRLF)为unix行尾换行符(LF):

find . -name '*.php' | xargs -I {} perl -pi -e 's/\r//g' {}

或者更简单点:

find . -name '*.cpp' | xargs sed -i 's/\r//g'

批量删除所有.svn子目录:

find . -type d -name ".svn"|xargs rm -rf

在整个文件系统查找名为 "emacs.desktop" 的文件, 并且忽略大小写:

find / -iname "emacs.desktop"

找出目录下所有".c"和".cpp"结尾的文件,统计它们一共有多少个:

ls -1 | grep -E '.(c|cpp)$' | wc -l

其中-E参数开启了扩展的正则表达式。

对目录下所有文件执行同种操作,比如文件名追加"pop":

for file in "$(ls)"; do echo -e "$file"pop; done

列出目录下所有png图片的绝对路径,并重定向到txt文件:

for f in `ls *.png`;do ls `pwd`/$f; done > img_list.txt 2>&1

列出目录下所有nv21图片,添加指定的前缀作为目录,并且按照自然顺序升序排序,并重定向到txt文件:

#PREFIX=`pwd`
PREFIX=/tmp/nfs/ld_testbed/LD_Test/test_image
for f in `ls -v *.nv21`;do echo $PREFIX/$f; done  > dir.txt 2>&1

其中ls -v是按自然顺序显示;也可以用 ls | sort -V 替代

计算md5加密:

echo -n "你的字符串" | openssl md5

其中-n参数一定要有,否则结果就不一样了(掺杂了回车的结果)

查看CPU是几核的:

cat /proc/cpuinfo | grep 'procossor' | wc -l

持续查看某条命令结果:用watch。例如每隔一秒监控一次nvidia显卡显存占用:

watch -n 1 nvidia-smi

列出目录下的文件,每行1个:

ls src -1  #-1表示每行1个

列出目录下文件,每行一个,并且加上路径名作为前缀:

ls src -1  | awk '{print "src/"$1}'

10.4 切换默认shell

默认shell是bash,希望切换到zsh。虽然我知道oh-my-zsh这样的很棒的库可以自动帮我们配置,不过我得经验是oh-my-zsh功能太多,我不需要。我是自行配置了自己的.zshrc。
从bash切换到zsh,不会影响到其他人。只需要:

chsh -s /usr/bin/zsh zz

然后重新登录(ssh的话重新连接)即可。

10.5 按文件大小列出文件

从大到小:du -sh * | sort -hr
从小到大:du -sh * | sort -h

10.6 排查环境变量在哪里被设定

譬如上面“中文显示为问号”的问题,找了另一台中文显示正常的镜像,知道$LANG环境变量需要配置,但不知道在哪里配置。网上很多博客提到/etc/environment里配置,但强迫症发现,正常显示中文的ubuntu系统中并不是在/etc/environment里配置的。

排查方法:
如果用zsh作为登录shell,则执行:

zsh -xl

bash的话则执行:

PS4='+$BASH_SOURCE> ' BASH_XTRACEFD=7 bash -xl 7>&2

这回模拟shell登录过程,显示所执行的操作。

对于bash,也可以输出到文件,而不是屏幕,方法是把7>&2换成7> file.log

PS4='+$BASH_SOURCE> ' BASH_XTRACEFD=7 bash -xl 7> file.log

如果这样并不能显示出想排查的环境变量,则依次检查:

  • ~/.ssh/environment
  • ~/.xinitrc
  • ~/.xsession
    如果还没有,则用find来检查:
find /etc/ -type f -exec grep -F THE_VAR {} +

参考:
https://unix.stackexchange.com/questions/813/how-to-determine-where-an-environment-variable-came-from

10.7 压缩解压相关

如下列出个人常用压缩解压命令的速查。如果没找到,可以从 tldr 命令查询。

.tar.gz

关键命令选项是"z"。不写"-",不写"z",都可以。
解压(到当前目录下):tar -zxvf xxx.tar.gz
解压到指定目录(应事先存在):tar -zxvf xxx.tar.gz -C /path/to/extract
压缩(某个目录):tar -zcvf xxx.tar.gz /some/path

.tar.bz2

关键命令选项是"j"。不写"-",不写"j",都可以。
解压(到当前目录下):tar -jxvf xxx.tar.bz2
解压到指定目录(应事先存在):tar -jxvf xxx.tar.bz2 -C /path/to/extract
压缩(某个目录):tar -jcvf xxx.tar.bz2 /some/path

.xz

关键命令选项是"J"。不写"-",不写"J",都可以。
解压(到当前目录下):tar -Jxvf xxx.tar.xz
解压到指定目录(应事先存在):tar -Jxvf xxx.tar.xz -C /path/to/extract
压缩(某个目录):tar -Jcvf xxx.xz /some/path

.zip

解压(到当前目录下):unzip xxx.zip
解压到指定目录(目录不存在则自动创建):unzip xxx.zip -d /path/to/extract
解压出来的文件名乱码(通常是Windows上创建的、文件名含有中文),指定编码即可解决:unzip -O CP936 xxx.zip
压缩(某个目录):zip -r xxx.zip /some/path
压缩某个目录,并且忽略 .gitbuild/linux-x64 目录: zip -r blunt.zip ./blunt -x '*.git*' -x '*build/linux-x64/*'

.rar

sudo apt install rar unrar  #注意apt源配置要配置multiverse

解压(到当前目录下):unrar e xxx.rar
解压到指定目录下(应事先存在):unrar x xxx.rar /path/to/extract

.gz
解压:
gzip -d xxx.gz
或:
gunzip xxx.gz

解压并且保留原始压缩文件:增加-c参数意思是输出到屏幕,可以进一步重定向到文件,从而实现了“解压并保留原文件”;

#解压并保留原文件
gunzip –c filename.gz > filename

#压缩并保留原文件
gzip –c filename > filename.gz 

例如mnist数据集用的就是.gz格式,解压命令为:

gzip -d t10k-images-idx3-ubyte.gz
gzip -d t10k-labels-idx1-ubyte.gz
gzip -d train-images-idx3-ubyte.gz
gzip -d train-labels-idx1-ubyte.gz

split切割文件
有时候文件很大很多,压缩后仍然很大,传输困难(例如单个文件超过磁盘大小,单个大文件ftp传输容易失败等),可以用split命令切割,然后再合并。

split是切割文件,不管它是压缩文件还是单个大文件。

举例:把googletest-release-1.8.0.tar.xz(560k),以50k为单位切割,切割后的文件们,名字前缀是"gtest.tar.zx_":

split googletest-release-1.8.0.tar.xz -b 50k gtest.tar.zx_

拼接回去:用cat命令:

cat gtest.tar.zx_* > gtest.tar.xz

unar命令

unar 支持多种压缩格式,并且在解压的时候能正确处理中文乱码。太好用了。(http://www.luoshuizhibin.cn/663.html)

unar xxx.zip
unar xxx.tar.gz
unar xxx.tar.bz2
...

注:ubuntu下测试,unar 的 v1.10.1 版本有 bug,具体变现:解压 xxx.tar.gz 后得到 xxx 目录,修改 xxx 目录内容,删除 xxx.tar.gz 并根据 xxx 目录重新创建 xxx.tar.gz,然后再用 unar 解压,结果得到的仍然是原始内容,而不是修改版的内容。

7z命令

7z 是跨平台的工具, 提供了界面和命令行。这里列出 7z 的命令行的一些用法:
解压:

# 解压一整个 zip 的全部内容到当前目录
7z x some_sdk.zip

# 解压时忽略 zip 中命为 PLATFORM 的目录
7z x some_sdk.zip -xr!PLATFORM

# 解压时忽略名为 ceres_d.lib 的库文件(位于深层子目录)
7z x some_sdk.zip '-xr!ceres_d.lib'

# 解压时忽略名为 opencv_ 开头的文件和目录
7z x some_sdk.zip '-xr!opencv_*'

# 解压时,同时忽略名为 PLATFORM 的目录, 以及 opencv 开头的库文件, 那就传入多个 -xr!
7z x some_sdk.zip -xr!PLATFORM '-xr!opencv_*'

10.8 重定向相关

覆盖
tee写入多行文件

tee xxx.txt << EOF
abc
def
EOF

追加
tee -a

tee -a xxx.txt << EOF
abc
def
EOF

使用变量时,用$替代$
这是个大坑。譬如想要append一些PATH的设定到~/.pathrc,这样写:

tee -a ~/.pathrc << EOF
export PATH=/usr/local/cuda-10.1/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-10.1/lib64:$LD_LIBRARY_PATH
EOF

然而打开~/.pathrc看,发现$PATH被展开了为$PATH的具体取值。。改正后的写法是:

tee -a ~/.pathrc << EOF
export PATH=/usr/local/cuda-10.1/bin:\$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-10.1/lib64:\$LD_LIBRARY_PATH
EOF

10.9 区分shell的外部命令和内置命令(builtin)

所谓builtin命令,是说只要在shell环境中就一定可以用的命令。例如pwd,cd。
而所谓外部命令,则需要通过查找PATH环境变量,找到后再执行。

判断一个命令是内部命令还是外部命令:type -a xxx,例如ls命令是一个外部命令:

type -a ls

输出:

ls is an alias for  ls --color=auto
ls is /bin/ls

pwd则是一个内置命令:

pwd is a shell builtin
pwd is /bin/pwd

其实可以省略-a参数。

shell获取所有的内置命令:对于不同的shell,内置命令很可能不同,获取内置命令的方式也有所差别。最常见的是bash和zsh。

bash获取所有内置命令:

compgen -b

bash和zsh都可以用来获取内置命令的命令:

while read -r _ cmd ; do echo $cmd ; done < <(enable -a)

(ref: How do I list all available shell builtin commands?)

上述命令,得到bash的内置命令有61个:

.
:
[
alias
bg
bind
break
builtin
caller
cd
command
compgen
complete
compopt
continue
declare
dirs
disown
echo
enable
eval
exec
exit
export
false
fc
fg
getopts
hash
help
history
jobs
kill
let
local
logout
mapfile
popd
printf
pushd
pwd
read
readarray
readonly
return
set
shift
shopt
source
suspend
test
times
trap
true
type
typeset
ulimit
umask
unalias
unset
wait

而zsh的内置命令则只有16个(这是enable -a的结果,感觉有点问题,不全)

cd'
-q'

-q'
st'
--color=auto'
-CF'
-A'
-al'
ls --color=auto'
-f'
-lF  | grep --color=never '\''^d'\'
-d */'
`pwd`/$1};lspwd'
-s http://wttr.in/\?m | head -n-1'

zsh用enable命令列出,则有103个内置命令:

-
.
:
[
alias
autoload
bg
bindkey
break
builtin
bye
cd
chdir
command
compadd
comparguments
compcall
compctl
compdescribe
compfiles
compgroups
compquote
compset
comptags
comptry
compvalues
continue
declare
dirs
disable
disown
echo
echotc
echoti
emulate
enable
eval
exec
exit
export
false
fc
fg
float
functions
getln
getopts
hash
history
integer
jobs
kill
let
limit
local
log
logout
noglob
popd
print
printf
pushd
pushln
pwd
r
read
readonly
rehash
return
sched
set
setopt
shift
source
suspend
test
times
trap
true
ttyctl
type
typeset
ulimit
umask
unalias
unfunction
unhash
unlimit
unset
unsetopt
vared
wait
whence
where
which
zcompile
zformat
zle
zmodload
zparseopts
zregexparse
zstat
zstyle

10.10 查看文件修改时间

当需要秒级的文件修改时间,windows的资源管理器中,默认显示的时间栏,只显示到分钟级别精度,并不够用

选中文件,右键->属性->常规,能看到秒级别的修改时间

在Linux下,则使用 stat 命令,查看文件的时间等属性

(base) localhost% stat 离前车很近.avi
  文件:'离前车很近.avi'
  大小:13413128        块:26200      IO 块:4096   普通文件
设备:811h/2065d        Inode:23465736    硬链接:1
权限:(0744/-rwxr--r--)  Uid:( 1010/      zz)   Gid:( 1010/      zz)
最近访问:2020-08-19 11:01:03.371964442 +0800
最近更改:2020-08-13 10:25:10.000000000 +0800
最近改动:2020-08-19 11:00:59.587710549 +0800
创建时间:-

stat命令最后四行给出了4种时间:

  • 最近访问(access time):读取操作,以及修改内容的操作,都会更改最近访问时间
  • 最近更改(modify time):对内容的修改被叫做"modify",最后一次修改内容的时间
  • 最近改动(change time):对文件属性的修改叫做"change",最后一次修改属性的时间

10.11 解压.z01格式的文件

file xxx.z01

类型为:

Zip multi-volume archive data, at least PKZIP v2.50 to extract

1).按下面提示方法, 安装7zip

sudo apt-get install p7zip-full
  1. .使用7z解压缩文件
7z x XXXX.zip

10.12 ls列出目录下文件,并且添加前缀

使用场景:CMakeLists.txt中添加某个目录下的文件,需要添加部分路径前缀。

for i in `ls -1`; do echo "src/operator/$i"; done

#得到:
src/operator/naive_convolution.c
src/operator/naive_convolution.h
src/operator/naive_pooling.c
src/operator/naive_pooling.h
src/operator/naive_relu.c
src/operator/naive_relu.h

10.13 替换tab(制表符)为空格

首先要理解制表符的目的,是为了制表,因此当输入tab键时,不一定是4空格的长度:

  • 如果tabsize等于8,那么在新起一行的输入tab键,将产生8空格长度
  • 我们假设tabsize等于4,那么按下tab键,可能得到4空格长度,也可能是3、2或1空格:只要结果能对齐到tabsize整数倍即可

ok,理解了tabsize和tab键的效果,下面来说如何替换这些“看起来宽度不等的tab”为空格:

expand src.c -t 4 > dst.c

-t 4 指定了 tabsize 为 4。

11. ubuntu包管理相关

11.1 卸载 dpkg 安装的软件

sudo dpkg -i xxx-X.Y.Z-Linux-x86_64.deb 安装的软件:

sudo apt remove xxx

举例:

sudo dpkg -i rr-5.5.0-Linux-x86_64.deb
sudo apt remove rr

11.2 aptitude查看包的简介:

aptitude show xxx

11.3. ubuntu查看某个软件包版本

对于已安装的软件包,用apt-show-versions:

# 安装
sudo apt install apt-show-versions

# 使用,举例
apt-show-versions colordiff

不管是否已经安装,都可以查询版本的方法:

sudo apt-cache madison <pkg_name>

例如

sudo apt-cache madison libopencv-dev

11.4. 查询Linux某命令来自哪个包

apt-file

安装和配置:

sudo apt-get install -y apt-file
sudo apt-file update

使用:apt-file search xxx,建议xxx用绝对路径。例如:

(base) localhost% which addr2line
/usr/bin/addr2line
(base) localhost% apt-file search /usr/bin/addr2line
binutils: /usr/bin/addr2line
binutils-multiarch: /usr/bin/addr2line

11.5 用aptitude查找包

aptitude search pkgName

pkgName可以有多个(空格分隔)

11.6 apt和dpkg相关命令整理

1. 文件->包

查询某文件属于哪个包
例如头文件(xxx.h, 编译问题)、库文件(xxx.so, 链接问题、运行问题)。

dpkg -S xxx, 需要包已经安装
例如dpkg -S libSPIRV-Tools-opt.so,返回:

spirv-tools: /usr/lib/x86_64-linux-gnu/libSPIRV-Tools-opt.so

apt-file -x search xxx,不需要包已经安装

2. 包->文件

dpkg -L xxx,需要包xxx已经安装

11.7 apt安装时报dpkg info错

例如samba-common包
dpkg:处理 samba-common (--configure)时出错: 子进程 已安装 post-installation 脚本 返回了错误号 10 dpkg:依赖关系问题使得 samba 的配置工作不能继续: samba 依赖于 samba-common (= 2:3.5.8~dfsg-1ubuntu2.3);然而: 软件包 samba-commo...

解决思路: 把/var/lib/dpkg/info/samba*文件挪走(似乎删除也没问题),然后apt remove samba,再apt install samba即可

如果不是samba而是其他软件包(例如apt-show-versions),则相应替换即可。

11.8 彻底关闭软件更新提示

每次开机后进桌面,都会弹出软件更新的窗口

希望关掉它,尝试了多种方法都无效,终极方法是sudo apt remove update-manager --purge。以下是不奏效方法的记录仅供参考

虽然有个设置按钮,点进去设置关闭各种更新,但重启后依然弹窗。

在设置页面看到说,snap的包仍然会自动提示。执行sudo snap list,发现都是核心的包,并没有安装VSCode和JDK,而弹窗中显示了它们。说明弹窗里的更新,和snap无关。

发现是apt默认配置的问题,通过改apt的配置文件,注释掉更新来解决:

sudo vim /etc/apt/apt.conf.d/99update-notifier

此文件只有两行,都含有update字段。行首添加#来注释:

11.9 卸载snap-store

ubuntu 20.04 的软件商店是 snap-store , 以前的版本是 gnome-store。 snap-store打开后,选择某个分类例如"Development",结果发现页面一片空白,等半小时能出现过一两次满是app logo的时候,但维持不到一分钟,页面再次变空白。

尝试过重装 snap-store ,问题依旧。卸载,装回gnome-store:

sudo snap remove snap-store
sudo snap install gnome-software

顺便说一下,snap并不需要snap-store,可以直接在 https://snapcraft.io/store 查找软件,然后用 sudo snap install xxx执行安装。

11.10 apt 安装 ripgrep 报错

dpkg: 处理归档 /var/cache/apt/archives/ripgrep_11.0.2-1build1_amd64.deb (--unpack)时出错:
 正试图覆盖 /usr/.crates2.json,它同时被包含于软件包 bat 0.12.1-1build1
dpkg-deb: 错误: 粘贴 子进程被信号(断开的管道) 终止了
在处理时有错误发生:
 /var/cache/apt/archives/ripgrep_11.0.2-1build1_amd64.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)

解决办法:
终端输入 sudo dpkg -i --force-overwrite /var/cache/apt/archives/*.deb 然后再执行就没问题了

ref: https://blog.csdn.net/yamanda/article/details/84967485

11.11 ubuntu 软件包管理相关

1 查找ppa软件包

经常发现ubuntu的apt提供的包版本太老,手动编译新版本实际上要自己手动解决依赖不方便,google/bing查找的话也比较凌乱。

实际上,直接从launchpad上就能找的。https://launchpad.net/ubuntu这里查找各种ppa提供的包。

(其实很久之前玩fedora的时候就用过类似的一个网站:pkgs.org,但是后来用ubuntu后就忘记了。。)

有些包用apt去装就可以了,或许需要添加ppa源;有些包则版本太老,需要从源码编译安装。

2 查找包

aptitude search pkgName

pkgName可以有多个(空格分隔)

3 安装软件到系统路径

有些软件包无法通过apt安装,例如CUDA;又或者,apt提供的安装包比较老/不全,希望自行编译安装,例如OpenCV、CMake、Protobuf。

其中,如果某个包主要对应一个可执行程序,比如cmake,而你希望apt安装的版本和自行编译安装的版本同时存在,那么安装到/usr/local/cmake-3.12这样的路径下就好了,通过~/.cmakerc中设定:

export PATH=/usr/local/cmake-3.12/bin:$PATH

并使用source ~/.cmakerc来临时切换版本。

而对于另外一些包,它被安装的目的可能更多的是提供一个.so,被其他程序连接,比如CUDA相关的libcudart.so,libcudnn.so等,以及OpenCV的各种库文件,则往往是在链接器相关的路径、环境变量上做游戏,例如写入到LD_LIBRARY_PATH,或者写入到/etc/ld.so.conf相应的配置文件+执行sudo ldconfig命令,来系统级的让相应的库文件被找到。
相关的,还有个LD_PRELOAD,可以用于同一个库的不同版本的先后查找配置上。

P.S. LD_PRELOAD用来指定动态库,用来给可执行文件的运行时切换库;LD_LIBRARY_PATH则是静态库(链接阶段)用的。

11.12 编译时提示头文件找不到

问题原因可能有多种。以caffe在ubuntu16.04上编译为例。

提示hdf5.h找不到。猜测是hdf相关的包的头文件不在系统的INCLUDE查找路径。

查找hdf相关的包。我记得自己装过,所以增加grep过滤:aptitude search hdf5 | grep '^i'

过滤查找结果中最可能的是-dev包。查看-dev包都安装了什么,分别装在哪里。因为确定是要找hdf5.h,所以依然grep过滤:dpkg -L libhdf5-dev | grep 'hdf5.h$'

结果是唯一的,/usr/include/hdf5/serial/hdf5.h。添加/usr/include/hdf5/serial到Caffe的Makefile中INCLUDE_DIRS变量上。

11.13 装ffmpeg

比如opencv调用网络摄像头 需要编解码支持 要用ffmpeg

sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next 
sudo apt-get update 
sudo apt-get install ffmpeg

(已失效,请用下面的:)

sudo apt-get install ppa-purge && sudo ppa-purge ppa:jonathonf/ffmpeg-4

11.14 千万别手贱执行sudo apt autoremove命令

这条命令对于初级中级用户来说,等同于"sudo rm -rf /*"一样危险,很容易毁掉整个Linux系统,基本上要重装的节奏。

解释:autoremove是说删除不需要的依赖,通常在执行apt install/remove后会“友好”地提示说:

The following packges were automatically installed and are no longer required:
....
Use 'sudo apt autoremove' to remove them.

然而实际上这个提示简直是坑爹,因为autoremove是说把你指定的包的依赖包都删掉。比如我要autoremove libreoffice,那么会把libreofflice***开头的库删掉。问题是,这些库很可能被其他正在用的软件依赖(例如firefox)。也就是:要autoremove A,那么A依赖的B也被删除,而autoremove并会去检查发现B被正在用的C所依赖,导致C也不能使用,而C往往是众多的,例如ubuntu的桌面。所以,autoremove是株连九族的暴力指令,没有十足的把握不要用,而ubuntu在apt get/remove等命令执行的最后提示的autoremove非常误导人,其心可诛

11.15 查询某个 apt 包的依赖和反向依赖

正向依赖

apt-cache depends <PkgName>

例如:

apt-cache depends xserver-xorg-video-nouveau
xserver-xorg-video-nouveau
  依赖: libc6
  依赖: libdrm-nouveau2
  依赖: libdrm2
  依赖: libudev1
  依赖: <xorg-video-abi-24>
    xserver-xorg-core
  依赖: xserver-xorg-core
  推荐: libgl1-mesa-dri
  建议: <firmware-misc-nonfree>

反向依赖

查询某个 apt 包依赖了哪些包:

apt-cache rdepends <PkgName>

例如:

apt-cache rdepends xserver-xorg-video-nouveau

得到:

xserver-xorg-video-nouveau
Reverse Depends:
  xserver-xorg-video-all
  xserver-xorg-video-nouveau-hwe-18.04

带递归的查询

sudo apt install apt-rdepends

然后执行正向依赖查询:

apt-rdepends <PkgName>

执行反向依赖查询:

apt-rdepends --reverse <PkgName>

12. 中文乱码问题

12.1 中文乱码

在使用某些docker镜像时,NFS挂载的磁盘上,中文目录显示为一串问号。应该是镜像本身不是中文版的缘故,配置方法:

安装中文语言包

apt install language-pack-zh-hans

配置 locale

apt install locales
locale-gen zh_CN.utf8
update-locale

编辑/etc/default/locale,添加:

LANG="zh_CN.UTF-8"
LANGUAGE="zh_CN:zh"

退出重连ssh即可显示。

参考:
https://askubuntu.com/questions/162391/how-do-i-fix-my-locale-issue

13. Linux软件安装和使用

13.1 JetBrain CLion破解

ubuntu desktop版本用来写代码 + cmake + CLion,调试方便。

最新版CLion破解:https://gitee.com/pengzhile/jetbrains-agent
目前已经完全切换到 VSCode + CodeLLDB + Clangd + CMake 插件的配置。 如果要用 CLion, 建议开发开源项目, 然后向 JetBrains 发邮件申请。

13.2 安装qq

先利用ppa源,安装wine:

sudo add-apt-repository ppa:wine/wine-builds  
sudo apt-get update
sudo apt-get install winehq-devel

然后下载wine版QQ:
链接: https://pan.baidu.com/s/1QK5HVh23dlZNMQg9ifIEKw 提取码: f2pr 复制这段内容后打开百度网盘手机App,操作更方便哦

tar xvf wineQQ8.9_19990.tar.xz -C ~/

按Win窗键,输入qq,打开QQ。第一次启动会提示安装必要的组件。装好组件后可以登录使用。

ref: https://www.cnblogs.com/zllwxm123/p/8512642.html

13.3 ubuntu不显示调节声音的图标

某天打开Ubuntu16.04桌面,发现Unity状态栏(桌面右上方)的声音调节图标不见了。虽然可以到设置->声音中调整,不过不方便。
印象中新装的系统是有这个图标的,可能是之前误操作删除了一些apt的包导致的。

解决办法:

sudo apt-get install indicator-sound -y
gsettings set com.canonical.indicator.sound visible true
sudo apt-get install unity-control-center

然后登出(logout)当前用户,重新登录进来;或者重启系统也可以。之后就可以看到声音图标了。

参考: Missing sound volume icon on screen top (14.04)

13.4 安装VSCodium

# add key
wget -qO - https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg | sudo apt-key add - 

# add repo
echo 'deb https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/repos/debs/ vscodium main' | sudo tee --append /etc/apt/sources.list.d/vscodium.list 

# update & install
sudo apt update && sudo apt install codium 

13.5 安装 flash

sudo apt-get install flashplugin-installer

13.6 安装deepin-terminal

sudo apt install deepin-terminal

默认是透明效果;默认配色主题对于ubuntu20.04(gnome)不太合适,tig界面中的字看不清,我换了argonaut主题:

13.7 安装deepin-screenshot

gnome-screenshot 截图后不能添加框、不能添加文字。deepin-screenshot可以:

sudo apt install deepin-screenshot

13.8 换新版git

不想升级 ubuntu 16.04,同时又想升级 git 来支持 husky + git hook 配置检查每次 git commit message 是否符合规范。那么用 PPA 的git:

sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git

13.9 安装最新版emacs

当不得不只能通过ssh连接到linux服务器进行C++开发时,我选择使用emacs。ubuntu16.04自带的emacs是24版,用我的配置文件会出现打开emacs后卡死在加载配置文件上的问题。索性安装最新版emacs(27):

#(emacs-snapshot 是最新版本,更新速度相对较快) 
sudo add-apt-repository ppa:ubuntu-elisp/ppa 
sudo apt update 
sudo apt install emacs-snapshot emacs-snapshot-el

13.10 Dolphin 中右键解压的 NDK, CMake 使用报错

检查了 NDK 的 .zip 压缩包的 md5sum, 和官网一致。然后在“解压 - 用cmake调用”的过程中出现了幺蛾子:

CMake 不识别 NDK-r24-beta, NDK-r23b 也遇到几乎一样的问题。之前傻傻的去 NDK 官方发 issue,官方表示说不能复现
https://github.com/zchrissirhcz/min-repros/tree/master/test_cmake_ndk-r24

一番检查, 终于发现原因:Dolphin右键解压,和用命令行解压,得到的NDK目录里文件不一样!

解压的过程是这样的:

这个右键解压的程序是 Ark,看来有 bug, 不能正确处理压缩目录中的软链接。

已经有人在 KDE 官方报告了 bug: https://bugs.kde.org/show_bug.cgi?id=415723

13.11 搜狗拼音输入法

不显示托盘

所谓托盘指的是:

能够输入中文,但是不显示托盘。那么当前的输入法很可能不是搜狗输入法。解决办法是在输入法->右键设置,把搜狗输入法置顶:

中文输入法时输入英文,然后按回车,输出了全角字符,希望输出正常的(半角)字符

切换到搜狗输入法即可。解决步骤和前面 “不显示托盘” 问题一样。

ctrl+space切换输入法后,希望切换到英文输入状态,但显示为五笔输入状态?

可能是误触 ctrl + shift 快捷键了。
右键输入法快捷图标,进入设置, 查看确认输入法之间的切换快捷键:

然后多按几次 ctrl + shift (或你的切换快捷键),每次按下后托盘会显示当前的输入法,直到切换到纯英文。

13.12 让 CLion 加载 ~/.zshrc, 加载环境变量

~/.zshrc~/.bashrc 里配置了环境变量,如 PATH, 或 CC, CXX 用来切换编译器, 或 ARTIFACTS_DIR 用来找本地的库(被cmake依赖),而默认 CLion(我用的2021.3版本)打开后执行 cmake 构建, 并没有加载 ~/.zshrc~/.bashrc

解决方法是修改 CLion 启动脚本中执行的命令。具体步骤:

  1. CLion 打开后的主界面(进入具体项目之前),左下角的齿轮点开, Create New Entry, 会在 /usr/share/applications 目录创建 jetbrains-clion.desktop 文件(快捷方式)

  1. 修改上述 desktop 快捷方式文件, 把 Exec 一行从原来的
Exec="/home/zz/soft/clion-2021.3/bin/clion.sh" %f

修改为:

Exec=bash -i -c "/home/zz/soft/clion-2021.3/bin/clion.sh" %f

  1. 删掉原来工程的 .ideacmake-build-debug 目录, 重开 CLion, 重新自动 cmake, 就会加载环境变量了

ref: https://developpaper.com/how-to-configure-ros-project-in-clion/

13.13 valgrind报错VEX temporary storage exhausted

在ubuntu16.04上测试LazyNet时出现的报错。原本执行的命令:

valgrind --tool=memcheck --leak-check=yes ./lazynet

尝试过指定vex参数为25:( 参考1, 参考2 )

valgrind --tool=memcheck --leak-check=yes ./lazynet --vex-guest-max-insns=25

但报错不变。

卸载了apt安装的valgrind,转为源码编译安装:

sudo apt remove valgrind -y
cd ~/work
wget https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2
tar -jxvf valgrind-3.15.0
cd valgrind-3.15.0
./autogen.sh
./configure --prefix=/home/zz/soft/valgrind
make -j8
make install

给PATH环境变量首部添加(append)valgrind安装后的bin目录

vim ~/.zshrc
export PATH=/home/zz/soft/valgrind/bin:$PATH

重开terminal,重新执行valgrind内存泄漏检测即可:

valgrind --tool=memcheck --leak-check=yes ./lazynet

13.14 耳机插入后没声音

需要手动设置下:

sudo apt install alsa
sudo apt install pavucontrol
pavucontrol  #打开了音量控制中心的GUI界面,然后手动选择输出设备为headphone

参考:
http://www.linuxdiyf.com/linux/25058.html

实测发现,我的显卡是GTX1080Ti,显卡内置了声卡,并且耳机插在屏幕上,屏幕和主机用DP线连接,Windows下有声音,Ubuntu下默认没声音,按上面链接里的设定不起作用,正确的设定是:

启发我的博客:https://blog.csdn.net/zz2230633069/article/details/85958197

P.S. 后来换了 KDE Plasma 桌面, 耳机设置的地方改为:

13.15 svn1.6在centos6下的使用

之前用centos6.5的时候 懒得手动编译高版本svn,用的是1.6版的,写了一些笔记:
http://www.cnblogs.com/zjutzz/p/4887288.html

其实如果可以还是用更新版本的svn吧,bug少,操作更人性化。

13.16 pureftp在centos下与MySQL搭配使用

之前用pureftp作为ftp的服务端软件,写了一些笔记:
http://www.cnblogs.com/zjutzz/p/4993106.html

其实如果只是内网使用服务器,比如Deep Learning日常连接到服务器做训练、测试、开发,用sftp就好了,简单省事。

13.17 配置samba服务器

使用场景:在windows系统上访问linux主机/服务器上的目录、文件。
在ubuntu16.04上配置如下:
1)关防火墙

//sudo ufw enable        //开启。这里仅作为备注,请不要执行这句。否则ssh很可能无法连接。
sudo ufw disable      //关闭防火墙 
sudo ufw status   //查看状态 
  1. 安装samba包
sudo apt-get install samba
  1. 改配置文件
sudo vim /etc/samba/smb.conf

配置项参考:https://blog.csdn.net/lan120576664/article/details/50396511

这里还需要注意目录权限问题。比如/home/tony的目录默认只能tony或者tony组的访问,其他用户不能访问。

并且注意:配置/etc/smb.conf中使用@tony表示tony组,而tony则表示用户tony

  1. 添加samba用户并设置密码
    要求用户必须是已经存在的linux用户
sudo smbpasswd -a chris

表示的是添加chris用户,然后输入samba访问的密码。

5)修改samba密码
管理员为了方便可以把每个用户的samba账号和密码设定为相同,或者都是123456这种密码。但是每个人的安全需要自行保证,每个用户应该可以自行修改密码。

管理员账号修改某个samba账号的密码:

sudo smbpasswd wjj

然后输入两次新密码即可

普通用户修改自己的samba密码:

smbpasswd

然后先输入原有密码,再输入两次新密码,注意新密码的长度要大于等于5个字符,否则会修改失败

6)设置目录权限
包括两种case:限制性访问,例如只读、只能浏览、只能某个用户或某个组有权限;另一种是所有人都有可读可写权限。这里说一下后者,先前一直被忽略了。。

先前一直忽略了这个配置的存在,导致想配置一个所有人public访问可读可写的目录失败。
ref: http://blog.sina.com.cn/s/blog_61b313a30101h199.html

ref: How to create a Samba share that is writable from Windows without 777 permissions?

仍然是需要创建用户的:

adduser --system shareuser
chown -R shareuser /path/to/share

Then add force user and permission mask settings in smb.conf:

[myshare]
path = /path/to/share
writeable = yes
browseable = yes
public = yes
create mask = 0644
directory mask = 0755
force user = shareuser
Note that guest ok is a synonym for public.
  1. 重启服务以生效
sudo service smbd restart

8)在windows上访问
打开资源管理器,地址栏输入"\172.17.xxx.xxx",这个是你的ubuntu的ip地址,可以通过ifconfig命令查看

  1. windows上清除访问凭证
    查看现有samba连接凭证:
net use 

清除某个凭证:net use \\172.17.89.33\some_dir /delete(感觉好像没有用)

control userpasswords2

用户管理->高级->密码管理->找到凭证并删除->重开资源管理器,地址栏重新输入目录

  1. 通过samba操作,解压、拷贝很慢,why?
    例如想要把A服务器上的B目录内容拷贝到/media/public,结果现在samba会先拷贝到本地,然后再传上去。而本机的网络传输速度很明显是小水管慢的很。

  2. 拷贝文件,samba提示空间不足,但是磁盘明明有空间?
    google了一番,发现问题在于samba的“挂载点”和系统磁盘挂载点不一致导致的。

譬如/etc/fstab中配置了/media/data1, /media/data2, 而/etc/samba/smb.conf中配置的是"/media",虽然访问起来方便了,但是拷贝很大(比如100G)的文件到data2的某个子目录,提示空间不足。就是因为"/media"在fstab中没有找到诶!主要改了smb.conf即可。

refs:

13.18 修改docker镜像的本地存储位置

最近用到一些docker镜像,里面放了海思等ADAS相关的工具链安装包,镜像特别大(5G~10G), 硬盘空间不足于是决定迁移。

实测靠谱的方法:

# 停服务
systemctl stop docker

# 搬数据. 预计10分钟或更久。
sudo su
mv /var/lib/docker /data/zz/docker

# 改配置
cd /etc/systemd/system
mkdir -p docker.service.d
vim docker.conf 

[Service] 

ExecStart= 

ExecStart=/usr/bin/dockerd --graph="/data/zz/docker" --storage-driver=devicemapper

# 重开服务
systemctl start docker

# 启镜像
docker run -it --rm some-image  bash

也就是从 /var/lib/docker 搬运到了 /data/zz/docker 目录。

注意:不能用"创建软链接“的方式替代配置文件。那样会导致无法启动镜像:

(base) zz@localhost% docker run -it --rm artifactory.xx.com.cn:6555/some_user/qnx-sdp
docker: Error response from daemon: OCI runtime create failed: /var/lib/docker/overlay2/32c596d3ce7448dbad011da948e62cdc17b85e7a68a98092023c3c1e2c437d03/merged is not an absolute path or is a symlink: unknown.

14 常见 vim 操作

14.1 鼠标粘贴

用鼠标复制内容到系统粘贴板后,粘贴到vim中,需要先开启paste(避免不正常的缩进),然后再粘贴

# 先按escape进入命令模式
:set paste
# 然后按i,进入insert模式
# 用鼠标粘贴

14.2 全局替换

:1,$s/old_string/new_string/g

解释:1,$表示从第一行到最后一行;s表示替代;old_string表示想要被替换掉的字符串(替换为new_string);g表示global,是说对于每一行,替换行内所有的old_string

14.3 vim全局查找

Esc
:%s/xxx/yyy/g

其中xxx是原始内容,yyy是替换后的内容

14.4 vim查找时忽略大小写/大小写敏感

:set ic

也就是

set ignorecase

来切换

14.5 sudo vim 和 vim 表现不一样

sudo vim xxxvim xxx,在ubuntu16.04上效果一致(高亮、行号...),都是用的~/.vimrc
ubuntu20.04上,sudo vim xxx没加载个人的vimrc,效果拉胯。

解决办法:sudo vim /etc/sudoers

修改

Defaults env_reset

Defaults !env_reset

重登shell即可

15. 其他杂项

15.1 编译安装opencv和opencv contrib 以及python接口

罗嗦版:http://www.cnblogs.com/zjutzz/p/6714490.html

mkdir -p ~/work/gitdown
cd $_
git clone https://github.com/opencv/opencv
git clone https://github.com/opencv/opencv_contrib
cd opencv
mkdir build
cd build
cmake \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_INSTALL_PREFIX=/usr/local/opencv-git-master \
-D WITH_CUDA=OFF \
-D WITH_VTK=OFF \
-D WITH_MATLAB=OFF \
-D BUILD_DOCS=ON \
-D OPENCV_EXTRA_MODULES_PATH=/home/chris/work/gitwhat/opencv_contrib/modules \
-D PYTHON2_EXECUTABLE=/usr/bin/python \
-D PYTHON3_EXECUTABLE=/usr/bin/python3 \
-D PYTHON_INCLUDE_DIR=/usr/include/python2.7 \
-D PYTHON_INCLUDE_DIR2=/usr/include/x86_64-linux-gnu/python2.7 \
-D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so \
-D PYTHON2_NUMPY_INCLUDE_DIRS=/usr/lib/python2.7/dist-packages/numpy/core/include/ \
-D PYTHON3_NUMPY_INCLUDE_DIRS=/usr/lib/python3.5/dist-packages/numpy/core/include/ \
..

期间容易出现ippicv等第三方包下载不下来的情况。找到对应的.cmake文件,把下载地址拼接出来自行下载,注意替换掉md5的hash值。下载的文件放到<opencv_root>/.cache目录下,例如:

.cache
├── ippicv
│   └── 1469ff5ced054be500921d2d46278ef4-ippicv_linux_20151201.tgz
├── protobuf
│   └── bd5e3eed635a8d32e2b99658633815ef-protobuf-cpp-3.1.0.tar.gz
├── tiny_dnn
│   └── adb1c512e09ca2c7a6faef36f9c53e59-v1.0.0a3.tar.gz
└── xfeatures2d
    ├── boostdesc
    │   ├── 0ae0675534aa318d9668f2a179c2a052-boostdesc_lbgm.i
    │   ├── 0ea90e7a8f3f7876d450e4149c97c74f-boostdesc_bgm.i
    │   ├── 202e1b3e9fec871b04da31f7f016679f-boostdesc_binboost_064.i
    │   ├── 232c966b13651bd0e46a1497b0852191-boostdesc_bgm_bi.i
    │   ├── 324426a24fa56ad9c5b8e3e0b3e5303e-boostdesc_bgm_hd.i
    │   ├── 98ea99d399965c03d555cef3ea502a0b-boostdesc_binboost_128.i
    │   └── e6dcfa9f647779eb1ce446a8d759b6ea-boostdesc_binboost_256.i
    └── vgg
        ├── 151805e03568c9f490a5e3a872777b75-vgg_generated_120.i
        ├── 7126a5d9a8884ebca5aea5d63d677225-vgg_generated_64.i
        ├── 7cd47228edec52b6d82f46511af325c5-vgg_generated_80.i
        └── e8d0dcd54d1bcfdc29203d011a797179-vgg_generated_48.i

新编译出来的cv2.so位于/usr/local/opencv-git-master/lib/cv2.so

sudo apt-get remove python-opencv
sudo ln -sf /usr/local/opencv-git-master/lib/python2.7/dist-packages/cv2.so /usr/lib/python2.7

或者设定PYTHONPATH也可以

15.2 编译安装protobuf3.2

apt装的protobuf是2.5版本. pip装的protobuf是3.2版。 使用了python layer的网络,如果用tools/caffe.cpp编译出的工具build/caffe来执行网络,会报protobuf版本问题,需要protobuf-cpp的版本装3.2版

编译装protobuf3.2

卸载apt的protobub

sudo apt-get remove --purge libprotobuf-dev

如果你是ubuntu-desktop用户,那你的桌面有可能被误删。立即安装(不要重启):

sudo apt-get install ubuntu-desktop -y
sudo apt-get install unity -y
sudo apt-get install compiz-gnome -y
sudo apt-get install libcompizconfig0 -y

静态编译protobuf(产生libprotobuf.a而不是.so文件,否则caffe编译会报错)

sudo apt-get install autoconf automake libtool curl make g++ unzip
cd ~/work/gitdown
git clone https://github.com/google/protobuf
cd protobuf
git checkout -b 3.2.x origin/3.2.x

./autogen.sh
vim configure

修改2658行和2661行,引号里面都换成"-fPIC"

./configure --disable-shared
make -j8
sudo make install

sudo ldconfig

重新编译caffe

cd ~/work/caffe-BVLC
make clean
make -j8
make pycaffe

15.3 py-faster-rcnn

http://www.cnblogs.com/zjutzz/p/6034408.html

15.4 sudo命令突然不能使用

有个师妹今天运行py-faster-rcnn代码来调用Matlab命令,提示matlab权限不足,但是修改权限时候不小心改了/usr路径的权限(大概是chown -R777 /usr这样,缺少了必要的空格,导致路径下文件的setuid权限出问题)。
总之,效果就是,sudo命令用不了了。
解决方法很简单:进入tty界面(ctrl+F1),用root登录,然后输入chmod -R 4755 /usr

当然,如果你仅仅是sudo命令本身不能用 那么就是chmod 4755 /usr/bin/sudo

参考:http://blog.csdn.net/shihuacai/article/details/14645447

15.5 编译安装protobuf3.2

apt装的protobuf是2.5版本. pip装的protobuf是3.2版。 使用了python layer的网络,如果用tools/caffe.cpp编译出的工具build/caffe来执行网络,会报protobuf版本问题,需要protobuf-cpp的版本装3.2版

编译装protobuf3.2

卸载apt的protobub

sudo apt-get remove --purge libprotobuf-dev

如果你是ubuntu-desktop用户,那你的桌面有可能被误删。立即安装(不要重启):

sudo apt-get install ubuntu-desktop -y
sudo apt-get install unity -y
sudo apt-get install compiz-gnome -y
sudo apt-get install libcompizconfig0 -y

静态编译protobuf(产生libprotobuf.a而不是.so文件,否则caffe编译会报错)

sudo apt-get install autoconf automake libtool curl make g++ unzip
cd ~/work/gitdown
git clone https://github.com/google/protobuf
git checkout -b 3.2.x origin/3.2.x
cd protobuf

vim configure

修改2658行和2661行,引号里面都换成"-fPIC"

./autogen.sh
./configure --disable-shared
make -j8
sudo make install

sudo ldconfig

重新编译caffe

cd ~/work/caffe-BVLC
make clean
make -j8
make pycaffe

refs

http://blog.csdn.net/linyushan11/article/details/10378419

https://github.com/BVLC/caffe/issues/19

15.6 ubuntu打开任意文件类似Mac--open和基本命令

xdg-open命令。
可以设定alias:

if [[ "$OSTYPE" == "linux-gnu"* ]]; then
    alias open='xdg-open'
fi

我这里.sh文件被用emacs打开了,不太习惯,在nautilus里邮件文件修改了默认打开方式。

15.7 双“重定向”

用caffe训练,产生log。想既在屏幕上看到实时log输出,也同时保存一份到文件。使用2>&1和tee命令,以及管道:

 ......caffe train --solver=......  2>&1 | tee log.txt  

15.7 VMWare 突然无法开机,Module 'Disk' power on failed.

按提示, 翻译过来是说无法开机, 原因是磁盘无法上电。 在前一天晚上虚拟机还是可以正常用的。尝试过重启 host, 以及重新创建虚拟机并复用磁盘文件,均失败。
解决办法: 重命名 vmdk.clk 文件, 例如增加 .backup 后缀, 就可以开启 VMWare 里的虚拟机了。

ref: https://blog.csdn.net/qq_38192709/article/details/119615428

16. Clang 无法使用,提示链接 -lstdc++ 失败

g++ 可以使用 (11.3.0), clang++ 则使用后报链接不上 libstdc++(包括 apt 官方仓库里的 clang++, 以及 llvm 官方最新的 15.0.7 的 clang++)。

尝试过安装 libstdc++-dev, 但不起作用。最后解决办法是试出来的:

sudo apt install libstdc++-12-dev

15.8 PowerShell 用法记录

测量某个命令的耗时

# 以 ls 命令为例. 会打印耗时,但看不到 ls 命令本身的输出
Measure-Command { ls }
# 测量 ls 命令的耗时, 同时保持 ls 命令本身的输出
Measure-Command { ls | Out-Default }

16. 2024年新学习使用的命令

16.1 查看文件大小

文件大小 和 文件占据磁盘空间大小 是不同的含义。

例如 mstore.c 内容如下:

long mult2(long, long);

void multstore(long x, long y, long* dest) {
    long t = mult2(x, y);
    *dest = t;
}

使用 ls -lh查看文件大小:

(base) zz@Legion-R7000P% ls -lh mstore.c
-rw-rw-r-- 1 zz zz 113  1月 19 21:55 mstore.c

使用 stat 命令查看文件大小:

(base) zz@Legion-R7000P% stat mstore.c
  文件:mstore.c
  大小:113             块:8          IO 块大小:4096   普通文件
设备:10302h/66306d     Inode:12592252    硬链接:1
权限:(0664/-rw-rw-r--)  Uid: ( 1000/      zz)   Gid: ( 1000/      zz)
访问时间:2024-01-19 21:56:02.907255654 +0800
修改时间:2024-01-19 21:55:48.526458420 +0800
变更时间:2024-01-19 21:55:48.526458420 +0800
创建时间:2024-01-19 21:55:48.526458420 +0800

使用 du -b 查看文件占据磁盘大小

(base) zz@Legion-R7000P% du -b mstore.c
113     mstore.c

使用 du -sh 查看文件占据磁盘大小

(base) zz@Legion-R7000P% du -sh mstore.c
4.0K    mstore.c

4KB, 这个结果太粗略和误导人。

总结

查看文件大小, 不要使用 du -sh, 它很不准确。请使用如下之一的命令查看字节大小:

ls -lh mstore.c
stat mstore.c
stat --format="%s" mstore.c

16.2 zsh 和 bash 的区别

当执行的命令中带有参数, 并且参数里含有中括号 [], 或者含有 backtick ```, 都不会被 zsh 正确识别,需要用双引号包起来:

./cpufp "--thread_pool=[0]"  # zsh, works
./cpufp --thread_pool=[0]  # bash works, zsh sucks

17. misc

17.1 修复 ubuntu 启动后进入 tty 并显示 Ctrl+D

2024-04-07 17:26:56

起因:

删除 docker 镜像时卡了,然后执行了docker的一些命令,但是docker服务还是不正常,于是重启。

发现关机关不上(或者是restart卡住了?)

尝试了在 grub 界面选旧一点的 kernel 但是无效。

解决办法: grub 界面选择 advanced, 按回车, 选择 kernel 最新的那个 Recovery。 会在 tty 界面执行 recovery, 进度到100%时弹出界面, 问是否要恢复, 选择默认的(恢复上一次启动),回车,就能进入桌面了。。神奇。

posted @ 2020-07-19 17:06  ChrisZZ  阅读(1004)  评论(51编辑  收藏  举报