Convolutional Neural Networks for Sentence Classification

https://arxiv.org/abs/1408.5882

github实现

https://github.com/yoonkim/CNN_sentence

https://github.com/Cheneng/TextCNN

对于文本分类,我们能不能用CNN来做,用某种模型初始化,进而做fine-tune呢?答案是肯定的,用于文本分析的CNN—TextCNN。

text-cnn用于情感分类:

与二维卷积层一样,一维卷积层使用一维的互相关运算。在一维互相关运算中,卷积窗口从输入数组的最左方开始,按从左往右的顺序,依次在输入数组上滑动。当卷积窗口滑动到某一位置时,窗口中的输入子数组与核数组按元素相乘并求和,得到输出数组中相应位置的元素。

多输入通道的一维互相关运算也与多输入通道的二维互相关运算类似:在每个通道上,将核与相应的输入做一维互相关运算,并将通道之间的结果相加得到输出结果。

由二维互相关运算的定义可知,多输入通道的一维互相关运算可以看作单输入通道的二维互相关运算。

类似地,我们有一维池化层。textCNN中使用的时序最大池化(max-over-time pooling)层实际上对应一维全局最大池化层:假设输入包含多个通道,各通道由不同时间步上的数值组成,各通道的输出即该通道所有时间步中最大的数值。因此,时序最大池化层的输入在各个通道上的时间步数可以不同。

简单来说,时序最大池化层就是沿着时序方向进行最大池化。

textCNN模型主要使用了一维卷积层和时序最大池化层。假设输入的文本序列由n个词组成,每个词用d维的词向量表示。那么输入样本的宽为n,高为1,输入通道数为d。textCNN的计算主要分为以下几步。(输入通道就是每个词的d为维度表示,宽就是时序长度)

词用d维的词向量表示 :一般使用词嵌入模型word2vec.

  1. 定义多个一维卷积核,并使用这些卷积核对输入分别做卷积计算。宽度不同的卷积核可能会捕捉到不同个数的相邻词的相关性。
  2. 对输出的所有通道分别做时序最大池化,再将这些通道的池化输出值连结为向量。
  3. 通过全连接层将连结后的向量变换为有关各类别的输出。这一步可以使用丢弃层应对过拟合。

下图用一个例子解释了textCNN的设计。这里的输入是一个有11个词的句子,每个词用6维词向量表示。因此输入序列的宽为11,输入通道数为6。给定2个一维卷积核,核宽分别为2和4,输出通道数分别设为4和5。因此,一维卷积计算后,4个输出通道的宽为11−2+1=10,而其他5个通道的宽为11−4+1=8。尽管每个通道的宽不同,我们依然可以对各个通道做时序最大池化,并将9个通道的池化输出连结成一个9维向量。最终,使用全连接将9维向量变换为2维输出,即正面情感和负面情感的预测。

Dive-into-DL-PyTorch
pytorch代码实现:
https://github.com/chenpaopao/TextCNN

总结:

  • 可以使用一维卷积来表征时序数据。
  • 多输入通道的一维互相关运算可以看作单输入通道的二维互相关运算。
  • 时序最大池化层的输入在各个通道上的时间步数可以不同。
  • textCNN主要使用了一维卷积层和时序最大池化层。
https://www.pexels.com/zh-cn/photo/977739/

torchtext.vocab的学习

NLP常见的数据预处理工作如下:

  1. Load File:数据文件加载;
  2. Tokenization:分词;
  3. Create Vocabulary:创建字典;
  4. Indexify:将词与索引进行映射;
  5. Word Vectors:创建或加载词向量;
  6. Padding or Fix Length:按长度对文本进行补齐或截取;
  7. Dataset Splits:划分数据集(如将数据集划分问训练集、验证集、测试集);
  8. Batching and Iterators:将数据集按固定大小划分成Batch;

使用torchtext完成以上工作:

  • 使用torchtext.data.Field定义样本各个字段的处理流程(分词、数据预处理等);
  • 使用torchtext.data.Example将torchtext.data.Field处理成一条样本;
  • 使用torchtext.data.Dataset将torchtext.data.Example处理成数据集,也可对数据集进行划分等工作;
  • 使用torchtext.data.Iterators将torchtext.data.Dataset按照batch_size组装成Batch供模型训练使用;
  • 使用torchtext.data.vocab和torchtext.data.Vectors创建词典、词和索引的一一对应、下载或使用预训练的词向量等;

  • vocab
  • 一句话概括主要是用来建立词汇表创建词典、词和索引的一一对应、下载或使用预训练的词向量等

    常见的词嵌入模型:word2vec Glove

    Pretrained Word Embeddings

    CLASS torchtext.vocab.GloVe(name='840B', dim=300, **kwargs)
    
    CLASS torchtext.vocab.FastText(language='en', **kwargs)
    
    CLASS torchtext.vocab.ChaarNGram(**kwargs)

    返回的实例主要有以下三个属性:

    • stoi: 词到索引的字典:
    • itos: 一个列表,索引到词的映射;
    • vectors: 词向量。

    通过上面的模块,实现由词到向量之间的转换!!!

    vocab.Vocab 是一个词汇表对象(由 下面的vocab 生成 Vocab 对象),使用counter创建词汇表

    collections.Counter 构建词汇表

    class collections.Counter([iterable-or-mapping])

    一个 Counter 是一个 dict 的子类,用于计数可哈希对象。它是一个集合,元素像字典键(key)一样存储,它们的计数存储为值。计数可以是任何整数值,包括0和负数。 Counter 类有点像其他语言中的 bags或multisets。Counter实际上也是dict的一个子类,之不多可以统计不同的值出现的次数。

    CLASS torchtext.vocab.Vocab(counter, max_size=None, min_freq=1, 
      specials=('<unk>', '<pad>'), vectors=None, unk_init=None, vectors_cache=None,
      specials_first=True)
      定义词汇表。属性:Vocab.freqs, Vocab.stoi, Vocab.itos
      __init__(counter,...)
          从 collections.Counter 构建词汇表
      load_vectors(vectors, **kwargs)
          vectors - GloVe, CharNGram, Vectors 实例,或者可用的预训练向量。
      set_vectors(stoi, vectors, dim, unk_init=...)
          从一个张量集合中设置词汇表实例的向量。
          stoi - 字符串 到 `vectors` 相应向量的索引 的字典
          vectors - 该参数支持索引 __getitem__。输入一个索引值,返回索引对应词条的向量(FloatTensor)。
                例如:vector[stoi["string"]] 应该返回 “string" 的词向量。
          dim - 词向量的维度

    torchtext.vocab.vocab 使用dict创建词汇表对象

    torchtext.vocab.vocabordered_dict: Dict , min_freq: int = 1 ) → torchtext.  vocab.Vocab[来源]

    用于创建将标记映射到索引的vocab对象的工厂方法。

    请注意,在构建vocab时,将遵守在ordered_dict中插入键值对的顺序。因此,如果按标记频率排序对用户很重要,则应以反映这一点的方式创建ordered_dict。

    参数

    • ordered_dict – 有序字典将标记映射到它们相应的出现频率。
    • min_freq – 在词汇表中包含一个标记所需的最小频率。

    Returns

    A Vocab objectReturn type

    torchtext.vocab.Vocab

    根据分好词的训练数据集来创建词典,过滤掉了出现次数少于5的词。

    
    #实例
    def get_vocab_imdb(data):
        tokenized_data = get_tokenized_imdb(data)
        counter = collections.Counter([tk for st in tokenized_data for tk in st])
        return Vocab.vocab(counter, min_freq=5)
    
    vocab = get_vocab_imdb(train_data)
    '# words in vocab:', len(vocab)
    
    输出:('# words in vocab:', 46151)
    
    

    SubwordVocab: 构建子词汇表

    CLASS torchtext.vocab.SubwordVocab(counter, max_size=None, specials='<pad>'
        vectors=None, unk_init=...)
      __init__(counter, ...)
          从 collections.Counter 构建子词词汇表,
          specials - padding or eos 等

    Vectors:返回词向量

    Look up embedding vectors of tokens

    CLASS torchtext.vocab.Vectors(name, cache=None, url=None, unk_init=None,
        max_vectors=None)
      __init__(name, cache=None, url=None, unk_init=None, max_vectors=None)
          name - 包含向量的文件名
          cache - 缓存向量文件的目录
          url - 如果缓存中没有找到向量文件,则从该链接下载
          max_vectors - 用于限制加载的预训练此向量的数量。大部分预训练的向量集都是按照词频降序排列
             在整个集合不适合内存或者不需要全部加载的情况下,可以加此限制。
      get_vecs_by_tokens(tokens, lower_case_backup=False)
          用于查找词条的嵌入向量。
          tokens - 一个词条或词条列表。如果一个词条,返回 self.dim 形状的一维张量;如果列表,返回
                 (len(tokens), self.dim)形状的二维张量。
          lower_case_backup -  是否查找小写的词条。如果为True,先按原格式在 `stoi` 查找,
                没找到的话,再查小写格式
    
    examples = ['chip', 'baby', 'Beautiful']
    vec = text.vocab.GloVe(name='6B', dim=50)
    ret = vec.get_vecs_by_tokens(tokens, lower_case_backup=True)

    build_vocab_from_iterator :从迭代器创建vocab

    torchtext.vocab.build_vocab_from_iterator(iterator, num_lines=None)
        从 迭代器 建立词汇表
        iterator - 必须产生词条的列表或迭代器
        num_lines - 迭代器返回元素的预期数量。
    
    
    torchtext.vocab.build_vocab_from_iterator(iterator: Iterable, min_freq: int = 1, specials: Optional[List[str]] = None, special_first: bool = True) → torchtext.vocab.vocab.Vocab[SOURCE]
    Build a Vocab from an iterator.
    
    Parameters
    iterator – Iterator used to build Vocab. Must yield list or iterator of tokens.
    
    min_freq – The minimum frequency needed to include a token in the vocabulary.
    
    specials – Special symbols to add. The order of supplied tokens will be preserved.
    
    special_first – Indicates whether to insert symbols at the beginning or at the end.
    https://pixabay.com/

    python 通过分享的链接下载抖音视频

    """下载抖音无水印的视频"""
    import re
    import requests
    
    useragent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36'
    headers = {'User-Agent': useragent}
    
    
    def dy_url_op(data):
        '''从data中找到url,返回str'''
        url=''
        url=re.findall(r'(https?://[^\s]+)',data)
        return url[0]
    
    def get_real_url(url,headers):
        session = requests.Session()
        req = session.get(url , timeout = 5 , headers = headers)
        vid = req.url.split("/")[4].split("?")[0]
        videoInfo = session.get("https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=" + vid,
            timeout = 5 , headers = headers)
        playAddr = re.findall(r'https://aweme.snssdk.com/aweme[\S]*?"',videoInfo.text)[0][:-1]
        parsedAddr = playAddr.replace("/playwm/","/play/")
        return vid, parsedAddr, session
    
    def downlowd_video(video_url):
        '''下载视频'''
        video_data=requests.get(video_url,headers=headers)
        with open('video.mp4','wb') as f:
            f.write(video_data.content)
    
    print("请输入如下格式:\n8.94 mdN:/ 孙红雷的瓜保熟么?%扫黑风暴开播   https://v.douyin.com/eEPNXH4/ 復制佌鏈接,打开Dou音搜索,直接观看视频!")
    data = input("请输入抖音视频链接:")
    vid, parsedAddr, session = get_real_url(dy_url_op(data),headers)
    downlowd_video(parsedAddr)
    print("下载完成!")

    爬虫过程中URL的变化:

    • 第1个URL(抖音分享的URL):https://v.douyin.com/JuGgK3M/
    • 第2个URL:https://www.iesdouyin.com/share/video/6893421572934159629/……
    • 第3个URL:https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=6893421572934159629
    • 第4个URL(视频URL):
      https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300f350000bul5ktfae8n8kibjf990&ratio=720p&line=0

    python 正则表达式和re模块

    正则表达式

    . 点号,在默认模式下,匹配除换行以外的任意字符。如果 DOTALL 标志被指定, 则匹配包括换行符在内的所有字符。

    ^    乘方运算符或脱字节符,在默认模式下匹配字符串的起始位置,在MULTILINE模式下也匹配换行符之后的位置。
    $    匹配字符串的末尾或者字符串末尾换行符之前的位置,在MULTILINE模式下还匹配换行符之前的位置。
    *    匹配前面重复出现的正则表达式零次或多次,尽可能多的匹配(greedy 贪婪型)。
    +    匹配前面RE 1次或多次(贪婪型,尽可能多的匹配)。
    ?    匹配前面的RE 0次或1次。
    *?,+?,??    '*'、'+'和'?'限定符是贪婪的;它们匹配尽可能多的文本。在限定符之后加上'?'将使得匹配以非贪婪的或最小的方式进行。
    {m}        表示精确匹配前面的正则表达式的m个拷贝,较少的匹配将导致整个表达式不能匹配。
    {m,n}    匹配前导正则表达式的m到n个重复,尝试匹配尽可能多的重复(greedy 贪婪型)。
    {m,}    匹配前导正则表达式的至少m次,尝试匹配尽可能多的重复(greedy 贪婪型)。
    {,n}    匹配前导正则表达式的至多n次,尝试匹配尽可能多的重复(greedy 贪婪型)。
    {m,n}?    匹配前导正则表达式的m到n个重复,尝试匹配尽可能少的重复(Non-greedy 非贪婪型)。
    \        对特殊符号进行转义
    []        用来表示一个字符集合。
            字符可以一个一个的列出来,如[abcd],则可以匹配'a','b','c','d'。
            通过给出两个字符并用'-'分隔,可以给出一段范围的字符,如[a-z]匹配小写字母,[A-Z]匹配大写字母,[0-9]匹配0-9的数字。
            在集合内部,特殊字符将失去它们特殊的含义,如[(+*)]将匹配'(','+','*',')'。
            在集合中接受字符类别\s,\S,\w等。
            可以使用[^RE]作为字符集的补集,^必须为集合第一个字符,如[^a-z]可以匹配除小写字母外所有的字符。
    |        a|b 匹配a或b,(Non-greedy 非贪婪型),匹配上正则a后,就不会再去尝试匹配正则b。
    (...)    被圆括号括起来的表达式将作为分组,分组表达式作为一个整体,后面可以接数量词,表达式中|仅在该组中有效。
            如(a-z|A-Z){2,3}表示匹配字母2至3次。
    (?aiLmsux)    给整个正则表达式设置相应的标记:re.A(ASCII码模式),re.I(忽略大小写),re.L(依赖区域设置);
                re.M(多行模式),re.S(点号匹配所有字符),re.U(依赖Unicode),re.X(详细模式)
    (?:...)    # 当你要将一部分规则作为一个整体对它进行某些操作,可以使用(?:RE)将正则表达式RE包裹起来。
    (?P<name>...)    # 将RE字符串包裹进来作为一个命名组。
    (?P=name)        # 使用命名组进行匹配。匹配前面定义的命名组匹配到的字符串。
    (?#...)            # 添加备注,忽略指定的字符。
    (?='...')        # 如果指定的字符在匹配到的字符后面,才算匹配成功。s='Isaac Asimov'   m=re.findall("Isaac (?=Asimov)",s)
    (?!...)            # 如果指定的字符不在匹配到的字符后面,才算匹配成功。s='Isaac Asimov'   m=re.findall("Isaac (?!Asimov)",s)
    (?<=...)         # 如果指定的字符在匹配到的字符前面,才算匹配成功。s='Isaac Asimov'   m=re.findall("(?<=Isaac )Asimov",s)
    (?<!...)        # 如果指定的字符不在匹配到的字符前面,才算匹配成功。s='Isaac Asimov'   m=re.findall("(?<!Isaac )Asimov",s)
    (?(id/name)yes|no)        #选择性匹配 (?(id/name)yes-pattern|no-pattern) 的作用是:
                                对于给出的id或者name,先尝试去匹配 yes-pattern部分的内容;
                                如果id或name条件不满足,则去匹配no-pattern部分的内容;no-pattern部分可以省略;
                                此处的name或id,是针对(当前位置的)条件性匹配之前的,某个已经通过group去分组的内容
                                如果是有命名的分组,即named group,则对应的该分组就有对应的name,即此处所指的就是对应的name;
                                如果是无命名的分组,即unnamed group,则对应的该分组也有对应的分组的编号,称为group的number,
                                也叫做id,对应的就是这里的id。
        *** 预定义字符集
    \\        匹配反斜杠
    \A        匹配字符串开头,同^
    \Z        匹配字符串结尾,同$
    \number    匹配相同编号的组的内容
    \b        匹配空字符串,仅在词的开头和结尾
    \B        匹配空字符串,不在词的开头和结尾,与\b相反
    \d        匹配数字,等同于[0-9]
    \D        匹配非数字,等同于\d的补集,即[^\d]
    \s        匹配whitespace字符串,同等于[ \t\n\r\f\v]
    \S        匹配非whitespace字符串,\s的补集,[^\s]
    \w        匹配字母,数字,下划线,等同于[a-zA-Z0-9_]
    \W        \w的补集

    使用re模块的步骤

    我们有必要对re模块中所包含的类及其工作流程进行一下简单的、整体性的说明,这讲有利于我们对下面内容的理解。

    使用re模块进行正则匹配操作的步骤:

    • 编写表示正则表达式规则的Python字符串str;
    • 通过re.compile()函数编译该Python字符串获得一个正则表达式对象(Pattern Object)p;
    • 通过正则表达式对象的p.match()或p.fullmatch()函数获取匹配结果–匹配对象(Match Object)m;
    • 通过判断匹配对象m是否为空可知是否匹配成功,也可以通过匹配对象m提供的方法获取匹配内容。

    使用re模块进行内容查找、替换和字符串分隔操作的步骤:

    • 编写表示正则表达式规则的Python字符串str;
    • 通过re.compile()函数编译该Python字符串获得一个正则表达式对象(Pattern Object)p;
    • 通过正则表达式对象的p.search()或p.findall()或p.finditer()或p.sub()或p.subn()或p.split()函数完内容查找、替换和字符串分隔操作并获取相应的操作结果;

    总结:

    • 根据上面的描述可知,将一个表示正则表达式的Python字符串编译成一个正则表达式对象是使用正则表达式完成相应功能的首要步骤.
    • re模块中用于完成正则表达式编译功能的函数为re.compile()。

    re.compile(patternflags=0)将正则表达式的样式编译为一个 正则表达式对象 (正则对象),可以用于匹配,通过这个对象的方法 match()search() 以及其他如下描述。

     

    prog = re.compile(pattern)
    result = prog.match(string)
    

    等价于

    result = re.match(pattern, string)
    re.search(patternstringflags=0)

    扫描整个 字符串 找到匹配样式的第一个位置,并返回一个相应的 匹配对象。如果没有匹配,就返回一个 None ; 注意这和找到一个零长度匹配是不同的。

    re.match(patternstringflags=0)

    如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的 匹配对象 。 如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。

    注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的开始位置,而不匹配每行开始。

    如果你想定位 string 的任何位置,使用 search() 来替代(也可参考 search() vs. match() )

    re.fullmatch(patternstringflags=0)

    如果整个 string 匹配到正则表达式样式,就返回一个相应的 匹配对象 。 否则就返回一个 None ;注意这跟零长度匹配是不同的。

    3.4 新版功能.

    re.split(patternstringmaxsplit=0flags=0)

    用 pattern 分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。

    re.findall(patternstringflags=0)

    Return all non-overlapping matches of pattern in string, as a list of strings or tuples. The string is scanned left-to-right, and matches are returned in the order found. Empty matches are included in the result.

    The result depends on the number of capturing groups in the pattern. If there are no groups, return a list of strings matching the whole pattern. If there is exactly one group, return a list of strings matching that group. If multiple groups are present, return a list of tuples of strings matching the groups. Non-capturing groups do not affect the form of the result.

     

    字符串分割

    使用re.split(pattern, string, maxsplit=0, flags=0)进行字符分割:

    字符串替换

    使用re.sub(pattern, repl, string, count=0, flags=0)对字符串进行替换:

    字符转义

    使用re.escape将所有字符转义:

    数据扩充和增广

    chenpaopao

    最近在学习 torch,对于图像数据的预处理, torchvision 提供了torchvision.transforms 模块,用于预处理。

    1. 1. 裁剪——Crop 中心裁剪:transforms.CenterCrop 随机裁剪:transforms.RandomCrop 随机长宽比裁剪:transforms.RandomResizedCrop 上下左右中心裁剪:transforms.FiveCrop 上下左右中心裁剪后翻转,transforms.TenCrop
    2. 2. 翻转和旋转——Flip and Rotation 依概率p水平翻转:transforms.RandomHorizontalFlip(p=0.5) 依概率p垂直翻转:transforms.RandomVerticalFlip(p=0.5) 随机旋转:transforms.RandomRotation
    3. 3. 图像变换 resize:transforms.Resize 标准化:transforms.Normalize 转为tensor,并归一化至[0-1]:transforms.ToTensor 填充:transforms.Pad 修改亮度、对比度和饱和度:transforms.ColorJitter 转灰度图:transforms.Grayscale 线性变换:transforms.LinearTransformation() 仿射变换:transforms.RandomAffine 依概率p转为灰度图:transforms.RandomGrayscale 将数据转换为PILImage:transforms.ToPILImage transforms.Lambda:Apply a user-defined lambda as a transform.
    4. 4. 对transforms操作,使数据增强更灵活 transforms.RandomChoice(transforms), 从给定的一系列transforms中选一个进行操作 transforms.RandomApply(transforms, p=0.5),给一个transform加上概率,依概率进行操作 transforms.RandomOrder,将transforms中的操作随机打乱

    此外,还提供了 torchvision.transforms.Compose( ),可以同时传递多个函数

    mytransform = transforms.Compose([
    transforms.ToTensor()
    ]
    )
    
    # torch.utils.data.DataLoader
    cifarSet = torchvision.datasets.CIFAR10(root = "../data/cifar/", train= True, download = True, transform = mytransform )
    cifarLoader = torch.utils.data.DataLoader(cifarSet, batch_size= 10, shuffle= False, num_workers= 2)
    >>> transforms.Compose([ 
    >>> transforms.CenterCrop(10),
    >>> transforms.PILToTensor(), >>> transforms.ConvertImageDtype(torch.float), >>> ])

    作为 Dataset类的参数传递 :

    torchvision.datasets.Caltech101(root: strtarget_type: Union[List[str], str] = ‘category’transform: Optional[Callable] = Nonetarget_transform: Optional[Callable] = Nonedownload: bool = False)

    或者自定义的类:
    (自己实现torchvision.datasets.CIFAR10的功能)

    (自己实现torchvision.datasets.CIFAR10的功能)
    import os
    import torch
    import torch.utils.data as data
    from PIL import Image
    
    def default_loader(path):
    return Image.open(path).convert('RGB')
    
    class myImageFloder(data.Dataset):
    def __init__(self, root, label, transform = None, target_transform=None, loader=default_loader):
    fh = open(label)
    c=0
    imgs=[]
    class_names=[]
    for line in fh.readlines():
    if c==0:
    class_names=[n.strip() for n in line.rstrip().split('    ')]
    else:
    cls = line.split()
    fn = cls.pop(0)
    if os.path.isfile(os.path.join(root, fn)):
    imgs.append((fn, tuple([float(v) for v in cls])))
    c=c+1
    self.root = root
    self.imgs = imgs
    self.classes = class_names
    self.transform = transform
    self.target_transform = target_transform
    self.loader = loader
    
    def __getitem__(self, index):
    fn, label = self.imgs[index]
    img = self.loader(os.path.join(self.root, fn))
    if self.transform is not None:
    img = self.transform(img)
    return img, torch.Tensor(label)
    
    def __len__(self):
    return len(self.imgs)
    def getName(self):
    return self.classes

    实例化torch.utils.data.DataLoader

    mytransform = transforms.Compose([
    transforms.ToTensor()
    ]
    )
    
    # torch.utils.data.DataLoader
    imgLoader = torch.utils.data.DataLoader(
    myFloder.myImageFloder(root = "../data/testImages/images", label = "../data/testImages/test_images.txt", transform = mytransform ),
    batch_size= 2, shuffle= False, num_workers= 2)
    
    for i, data in enumerate(imgLoader, 0):
    print(data[i][0])
    # opencv
    img2 = data[i][0].numpy()*255
    img2 = img2.astype('uint8')
    img2 = np.transpose(img2, (1,2,0))
    img2=img2[:,:,::-1]#RGB->BGR
    cv2.imshow('img2', img2)
    cv2.waitKey()
    break

    2 使用Python+OpenCV进行数据扩充(适用于目标检测)

    https://pythonmana.com/2021/12/202112131040182515.html

    下面内容来自

    数据扩充是一种增加数据集多样性的技术,无需收集更多真实数据,但仍有助于提高模型精度并防止模型过拟合。

    数据扩充方法包括:

    1. 随机裁剪
    2. Cutout
    3. 颜色抖动
    4. 增加噪音
    5. 过滤
    import os
    
    import cv2
    
    import numpy as np
    
    import random
    
    
    def file_lines_to_list(path):
    
        '''
    
        ### 在TXT文件里的行转换为列表 ###
    
        path: 文件路径
    
        '''
    
        with open(path) as f:
    
            content = f.readlines()
    
        content = [(x.strip()).split() for x in content]
    
        return content
    
    
    def get_file_name(path):
    
        
    '''
    
        ### 获取Filepath的文件名 ###
    
        path: 文件路径
    
        '''
    
        basename = os.path.basename(path)
    
        onlyname = os.path.splitext(basename)[0]
    
        return onlyname
    
    
    def write_anno_to_txt(boxes, filepath):
    
        
    '''
    
        ### 给TXT文件写注释 ###
    
        boxes: format [[obj x1 y1 x2 y2],...]
    
        filepath: 文件路径
        '''
    
        txt_file = open(filepath, "w")
    
        for box in boxes:
    
            print(box[0], int(box[1]), int(box[2]), int(box[3]), int(box[4]), file=txt_file)
    
        txt_file.close()

    随机裁剪

    随机裁剪随机选择一个区域并进行裁剪以生成新的数据样本,裁剪后的区域应具有与原始图像相同的宽高比,以保持对象的形状。

    def randomcrop(img, gt_boxes, scale=0.5):
    
        
    '''
    
        ### 随机裁剪 ###
    
        img: 图像
    
        gt_boxes: format [[obj x1 y1 x2 y2],...]
    
        scale: 裁剪区域百分比
        '''
    
    
        # 裁剪
    
        height, width = int(img.shape[0]*scale), int(img.shape[1]*scale)
    
        x = random.randint(0, img.shape[1] - int(width))
    
        y = random.randint(0, img.shape[0] - int(height))
    
        cropped = img[y:y+height, x:x+width]
    
        resized = cv2.resize(cropped, (img.shape[1], img.shape[0]))
    
    
        # 修改注释
    
        new_boxes=[]
    
        for box in gt_boxes:
    
            obj_name = box[0]
    
            x1 = int(box[1])
    
            y1 = int(box[2])
    
            x2 = int(box[3])
    
            y2 = int(box[4])
    
            x1, x2 = x1-x, x2-x
    
            y1, y2 = y1-y, y2-y
    
            x1, y1, x2, y2 = x1/scale, y1/scale, x2/scale, y2/scale
    
            if (x1<img.shape[1] and y1<img.shape[0]) and (x2>0 and y2>0):
    
                if x1<0: x1=0
    
                if y1<0: y1=0
    
                if x2>img.shape[1]: x2=img.shape[1]
    
                if y2>img.shape[0]: y2=img.shape[0]
    
                new_boxes.append([obj_name, x1, y1, x2, y2])
    
        return resized, new_boxes

    Cutout

    Terrance DeVries和Graham W.Taylor在2017年的论文中介绍了Cutout,它是一种简单的正则化技术,用于在训练过程中随机屏蔽输入的方块区域,可用于提高卷积神经网络的鲁棒性和整体性能。这种方法不仅非常容易实现,而且还表明它可以与现有形式的数据扩充和其他正则化工具结合使用,以进一步提高模型性能。如本文所述,剪切用于提高图像识别(分类)的准确性,因此,如果我们将相同的方案部署到对象检测数据集中,可能会导致丢失对象的问题,尤其是小对象。

    剪切输出是新生成的图像,我们不移除对象或更改图像大小,则生成图像的注释与原始图像相同。

    def cutout(img, gt_boxes, amount=0.5):
    
        
    '''
    
        ### Cutout ###
    
        img: 图像
    
        gt_boxes: format [[obj x1 y1 x2 y2],...]
    
        amount: 蒙版数量/对象数量
        '''
    
        out = img.copy()
    
        ran_select = random.sample(gt_boxes, round(amount*len(gt_boxes)))
    
    
        for box in ran_select:
    
            x1 = int(box[1])
    
            y1 = int(box[2])
    
            x2 = int(box[3])
    
            y2 = int(box[4])
    
            mask_w = int((x2 - x1)*0.5)
    
            mask_h = int((y2 - y1)*0.5)
    
            mask_x1 = random.randint(x1, x2 - mask_w)
    
            mask_y1 = random.randint(y1, y2 - mask_h)
    
            mask_x2 = mask_x1 + mask_w
    
            mask_y2 = mask_y1 + mask_h
    
            cv2.rectangle(out, (mask_x1, mask_y1), (mask_x2, mask_y2), (0, 0, 0), thickness=-1)
    
        return out

    颜色抖动

    ColorJitter是另一种简单的图像数据增强,我们可以随机改变图像的亮度、对比度和饱和度。我相信这个技术很容易被大多数读者理解。

    def colorjitter(img, cj_type="b"):
    
        
    '''
    
        ### 不同的颜色抖动 ###
    
        img: 图像
    
        cj_type: {b: brightness, s: saturation, c: constast}
        '''
    
        if cj_type == "b":
    
            # value = random.randint(-50, 50)
    
            value = np.random.choice(np.array([-50, -40, -30, 30, 40, 50]))
    
            hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    
            h, s, v = cv2.split(hsv)
    
            if value >= 0:
    
                lim = 255 - value
    
                v[v > lim] = 255
    
                v[v <= lim] += value
    
            else:
    
                lim = np.absolute(value)
    
                v[v < lim] = 0
    
                v[v >= lim] -= np.absolute(value)
    
    
            final_hsv = cv2.merge((h, s, v))
    
            img = cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR)
    
            return img
    
    
        elif cj_type == "s":
    
            # value = random.randint(-50, 50)
    
            value = np.random.choice(np.array([-50, -40, -30, 30, 40, 50]))
    
            hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    
            h, s, v = cv2.split(hsv)
    
            if value >= 0:
    
                lim = 255 - value
    
                s[s > lim] = 255
    
                s[s <= lim] += value
    
            else:
    
                lim = np.absolute(value)
    
                s[s < lim] = 0
    
                s[s >= lim] -= np.absolute(value)
    
    
            final_hsv = cv2.merge((h, s, v))
    
            img = cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR)
    
            return img
    
    
        elif cj_type == "c":
    
            brightness = 10
    
            contrast = random.randint(40, 100)
    
            dummy = np.int16(img)
    
            dummy = dummy * (contrast/127+1) - contrast + brightness
    
            dummy = np.clip(dummy, 0, 255)
    
            img = np.uint8(dummy)
    
            return img

    增加噪声

    在一般意义上,噪声被认为是图像中的一个意外因素,然而,几种类型的噪声(例如高斯噪声、椒盐噪声)可用于数据增强,在深度学习中添加噪声是一种非常简单和有益的数据增强方法。

    对于那些无法识别高斯噪声和椒盐噪声之间差异的人,高斯噪声的值范围为0到255,具体取决于配置,因此,在RGB图像中,高斯噪声像素可以是任何颜色。相比之下,椒盐噪波像素只能有两个值0或255,分别对应于黑色(PEPER)或白色(salt)。

    def noisy(img, noise_type="gauss"):
    
        
    '''
    
        ### 添加噪声 ###
    
        img: 图像
    
        cj_type: {gauss: gaussian, sp: salt & pepper}
        '''
    
        if noise_type == "gauss":
    
            image=img.copy() 
    
            mean=0
    
            st=0.7
    
            gauss = np.random.normal(mean,st,image.shape)
    
            gauss = gauss.astype('uint8')
    
            image = cv2.add(image,gauss)
    
            return image
    
    
        elif noise_type == "sp":
    
            image=img.copy() 
    
            prob = 0.05
    
            if len(image.shape) == 2:
    
                black = 0
    
                white = 255            
    
            else:
    
                colorspace = image.shape[2]
    
                if colorspace == 3:  # RGB
    
                    black = np.array([0, 0, 0], dtype='uint8')
    
                    white = np.array([255, 255, 255], dtype='uint8')
    
                else:  # RGBA
    
                    black = np.array([0, 0, 0, 255], dtype='uint8')
    
                    white = np.array([255, 255, 255, 255], dtype='uint8')
    
            probs = np.random.random(image.shape[:2])
    
            image[probs < (prob / 2)] = black
    
            image[probs > 1 - (prob / 2)] = white
    
            return image

    滤波

    本文介绍的最后一个数据扩充过程是滤波。与添加噪声类似,滤波也简单且易于实现。实现中使用的三种类型的滤波包括模糊(平均)、高斯和中值。

    def filters(img, f_type = "blur"):
    
        
    '''
    
        ### 滤波 ###
    
        img: 图像
    
        f_type: {blur: blur, gaussian: gaussian, median: median}
        '''
    
        if f_type == "blur":
    
            image=img.copy()
    
            fsize = 9
    
            return cv2.blur(image,(fsize,fsize))
    
    
        elif f_type == "gaussian":
    
            image=img.copy()
    
            fsize = 9
    
            return cv2.GaussianBlur(image, (fsize, fsize), 0)
    
    
        elif f_type == "median":
    
            image=img.copy()
    
            fsize = 9
    
            return cv2.medianBlur(image, fsize)

    上述内容可以在这里找到完整实现

    https://github.com/tranleanh/data-augmentation

    linux-11

    more命令:显示文件内容,类似cat

    Linux more 命令类似 cat ,不过会以一页一页的形式显示,更方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示,按 b 键就会往回(back)一页显示,而且还有搜寻字串的功能(与 vi 相似),使用中的说明文件,请按 h 。
    more命令和cat的功能一样都是查看文件里的内容,但有所不同的是more可以按页来查看文件的内容,还支持直接跳转行等功能。

    ps命令:任务管理器

    Linux中的ps命令是Process Status的缩写。ps命令用来列出系统中当前运行的那些进程。ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信息,就可以使用top命令。

    linux上进程有5种状态:

    运行(正在运行或在运行队列中等待)  
    中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号)  
    不可中断(收到信号不唤醒和不可运行, 进程必须等待直到有中断发生)  
    僵死(进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放)  
    停止(进程收到SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU信号后停止运行运行) 

    ps工具标识进程的5种状态码:

    D 不可中断 uninterruptible sleep (usually IO)
    R 运行 runnable (on run queue)
    S 中断 sleeping
    T 停止 traced or stopped
    Z 僵死 a defunct (”zombie”) process

    命令参数

    a 显示所有进程
    -a 显示同一终端下的所有程序
    -A 显示所有进程
    c 显示进程的真实名称
    -N 反向选择
    -e 等于“-A”
    e 显示环境变量
    f 显示程序间的关系
    -H 显示树状结构
    r 显示当前终端的进程
    T 显示当前终端的所有程序
    u 指定用户的所有进程
    -au 显示较详细的资讯
    -aux 显示所有包含其他使用者的行程
    -C<命令> 列出指定命令的状况
    –lines<行数> 每页显示的行数
    –width<字符数> 每页显示的字符数
    –help 显示帮助信息
    –version 显示版本显示

    输出列的含义

    F 代表这个程序的旗标 (flag), 4 代表使用者为 super user
    S 代表这个程序的状态 (STAT),关于各 STAT 的意义将在内文介绍
    UID 程序被该 UID 所拥有
    PID 进程的ID
    PPID 则是其上级父程序的ID
    C CPU 使用的资源百分比
    PRI 这个是 Priority (优先执行序) 的缩写,详细后面介绍
    NI 这个是 Nice 值,在下一小节我们会持续介绍
    ADDR 这个是 kernel function,指出该程序在内存的那个部分。如果是个 running的程序,一般就是 “-“
    SZ 使用掉的内存大小
    WCHAN 目前这个程序是否正在运作当中,若为 - 表示正在运作
    TTY 登入者的终端机位置
    TIME 使用掉的 CPU 时间。
    CMD 所下达的指令为何

    htop 任务管理器(apt install htop)

    命令:htop
    在按F5,树型显示进程

    杀死进程 kill

    kill -9 进程id
    
    注意 pid 为进程id
        ppid为父一级的id

    查看进程号 lsof -i:

    sudo netstat -antup
    
    1、lsof -i:端口号
    
    2、netstat -tunlp | grep 端口号

    模式扩展

    ? 匹配单个字符,包括空字符(不会匹配隐藏文件)
    * 匹配任意个字符,不会匹配隐藏文件
    [1-9]匹配【】中的字符
    [!1234] 匹配【】之外的符号
    {1,2,3,4,5}  会分别输出1,2,3,4,5,
    echo 1{2,3,4,5}1
    输出:121 131 141 151

    单引号

    单引号用于保留字符的字面含义,各种特殊字符在''单引号里面都会变成普通的字符,比如* $ \

    双引号

    双引号作用同单引号,但特别的是:不会转义 $ ` \ 这三个符号

    总之:可以认为双引号可以包含变量($符号仍然起作用)

    输入输出重定向

    将原始键盘输入、屏幕输出 转变为文件输入、输出到文件

    输入重定向 < 和<<

    <
    <<
    例如:cat <file1
    将file1的内容输入到cat中

    输出重定向 >> 和 >

    命令>1.txt 2>error.txt
    将错误信息输出到error中,正确信息输出到1.txt中

    总结 命令>1.txt 2>error.txt &

    命令 & 可以后台执行命令

    过滤器

    wc 命令

    Linux系统中的wc(Word Count)命令的功能为统计指定文件中的字节数、字数、行数,并将统计结果显示输出。
    统计指定文件中的字节数、字数、行数,并将统计结果显示输出。该命令统计指定文件中的字节数、字数、行数。如果没有给出文件名,则从标准输入读取。wc同时也给出所指定文件的总统计数。

    命令参数:

    -c 统计字节数。
    
    -l 统计行数。
    
    -m 统计字符数。这个标志不能与 -c 标志一起使用。
    
    -w 统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
    
    -L 打印最长行的长度。
    
    -help 显示帮助信息
    
    --version 显示版本信息

    grep 搜索命令

    Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

    grep的工作方式是这样的,它在一个或多个文件中搜索字符串模板。如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名。搜索的结果被送到标准输出,不影响原文件内容。

    grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在,则返回2。我们利用这些返回值就可进行一些自动化的文本处理工作。

    grep [option] pattern file

    grep rnn test.txt  #在test.txt中搜索rnn

    命令参数:

    -a   --text   #不要忽略二进制的数据。   
    
    -A<显示行数>   --after-context=<显示行数>   #除了显示符合范本样式的那一列之外,并显示该行之后的内容。   
    
    -b   --byte-offset   #在显示符合样式的那一行之前,标示出该行第一个字符的编号。   
    
    -B<显示行数>   --before-context=<显示行数>   #除了显示符合样式的那一行之外,并显示该行之前的内容。   
    
    -c    --count   #计算符合样式的列数。   
    
    -C<显示行数>    --context=<显示行数>或-<显示行数>   #除了显示符合样式的那一行之外,并显示该行之前后的内容。   
    
    -d <动作>      --directories=<动作>   #当指定要查找的是目录而非文件时,必须使用这项参数,否则grep指令将回报信息并停止动作。   
    
    -e<范本样式>  --regexp=<范本样式>   #指定字符串做为查找文件内容的样式。   
    
    -E      --extended-regexp   #将样式为延伸的普通表示法来使用。   
    
    -f<规则文件>  --file=<规则文件>   #指定规则文件,其内容含有一个或多个规则样式,让grep查找符合规则条件的文件内容,格式为每行一个规则样式。   
    
    -F   --fixed-regexp   #将样式视为固定字符串的列表。   
    
    -G   --basic-regexp   #将样式视为普通的表示法来使用。   
    
    -h   --no-filename   #在显示符合样式的那一行之前,不标示该行所属的文件名称。   
    
    -H   --with-filename   #在显示符合样式的那一行之前,表示该行所属的文件名称。   
    
    -i    --ignore-case   #忽略字符大小写的差别。   
    
    -l    --file-with-matches   #列出文件内容符合指定的样式的文件名称。   
    
    -L   --files-without-match   #列出文件内容不符合指定的样式的文件名称。   
    
    -n   --line-number   #在显示符合样式的那一行之前,标示出该行的列数编号。   
    
    -q   --quiet或--silent   #不显示任何信息。   
    
    -r   --recursive   #此参数的效果和指定“-d recurse”参数相同。   
    
    -s   --no-messages   #不显示错误信息。   
    
    -v   --revert-match   #显示不包含匹配文本的所有行。   
    
    -V   --version   #显示版本信息。   
    
    -w   --word-regexp   #只显示全字符合的列。   
    
    -x    --line-regexp   #只显示全列符合的列。   
    
    -y   #此参数的效果和指定“-i”参数相同。
    ps命令常用用法(方便查看系统进程)
    
    1)ps a 显示现行终端机下的所有程序,包括其他用户的程序。
    
    2)ps -A 显示所有进程。
    
    3)ps c 列出程序时,显示每个程序真正的指令名称,而不包含路径,参数或常驻服务的标示。
    
    4)ps -e 此参数的效果和指定"A"参数相同。
    
    5)ps e 列出程序时,显示每个程序所使用的环境变量。
    
    6)ps f 用ASCII字符显示树状结构,表达程序间的相互关系。
    
    7)ps -H 显示树状结构,表示程序间的相互关系。
    
    8)ps -N 显示所有的程序,除了执行ps指令终端机下的程序之外。
    
    9)ps s 采用程序信号的格式显示程序状况。
    
    10)ps S 列出程序时,包括已中断的子程序资料。
    
    11)ps -t<终端机编号>  指定终端机编号,并列出属于该终端机的程序的状况。
    
    12)ps u  以用户为主的格式来显示程序状况。
    
    13)ps x  显示所有程序,不以终端机来区分。
    
    最常用的方法是ps -aux,然后再利用一个管道符号导向到grep去查找特定的进程,然后再对特定的进程进行操作。

    nohup 不挂断地运行命令

    用途:不挂断地运行命令。

    语法:nohup Command [ Arg … ] [ & ]

      无论是否将 nohup 命令的输出重定向到终端,输出都将附加到当前目录的 nohup.out 文件中。

      如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。

      如果没有文件能创建或打开以用于追加,那么 Command 参数指定的命令不可调用。

    退出状态:该命令返回下列出口值:   
      126 可以查找但不能调用 Command 参数指定的命令。   
      127 nohup 命令发生错误或不能查找由 Command 参数指定的命令。   
      否则,nohup 命令的退出状态是 Command 参数指定命令的退出状态。

    2.&

    用途:在后台运行

    一般两个一起用

    nohup command &

    重点记忆

    nohup 命令>1.txt 2>error.txt &

    反引号 “ ==$()

    这个东西的用法,我百度了一下,和$()是一样的。在执行一条命令时,会先将其中的 “,或者是$() 中的语句当作命令执行一遍,再将结果加入到原命令中重新执行,例如:

    echo `ls`

    会先执行 ls 得到xx.sh等,再替换原命令为:

    echo xx.sh

    最后执行结果为

    xx.sh

    新建子 shell :bash命令

    $ bash

    子 Shell 是由 Shell 或 Shell 脚本运行的子进程。当我们在 Shell 命令行提示符下,运行一个 Shell 脚本时,它会创建一个叫做子 Shell 的新进程,我们的脚本将会使用这个子 Shell 来运行。

    子 Shell 是命令处理程序(提供给我们命令行提示符的 Shell 或是一个 xterm 窗口)的一个单独实例。就像我们的命令在命令行提示符下被解释,类似地,脚本批处理一连串命令。实际上,每个运行的 Shell 脚本都是父 Shell 的子进程。

    退出子shell : exit命令

    exit

    产生子Shell
    执行 bash命令本身
    显然它会进入子shell环境,它的绝大多数环境都是新配置的,因为会加载一些环境配置文件。事实上fork出来的bash子进程内容完全继承父shell,但因重新加载了环境配置项,所以子shell没有继承普通变量,更准确的说是覆盖了从父shell中继承的变量
    当前 Shell 及随后新建的子 Shell,都可以读取变量$NAME。

    子 Shell 如果修改继承的变量,不会影响父 Shell。

    # 输出变量 $foo
    $ export foo=bar
    
    # 新建子 Shell
    $ bash
    
    # 读取 $foo
    $ echo $foo
    bar
    
    # 修改继承的变量
    $ foo=baz
    
    # 退出子 Shell
    $ exit
    
    # 读取 $foo
    $ echo $foo
    bar

    linux命令学习

    linux命令学习

    1. sort 对行排序命令

    sort是对行排序!!!每一行的前后顺升序排序

    sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。

    sort文件名> newfile
    将文件排序后的输出到newfile,是用输出重定向,如果不使用,那么只会在屏幕上输出排序的结果,原始文件内容不会改变

    sort的-u选项
    
    它的作用很简单,就是在输出行中去除重复行。
    
     sort的-r选项:降序排序
    
    sort默认的排序方式是升序,如果想改成降序,就加个-r就搞定了。
    
    sort的-o选项:输出到原始文件
    
    由于sort默认是把结果输出到标准输出,所以需要用重定向才能将结果写入文件,形如sort filename > newfile。
    
    但是,如果你想把排序结果输出到原文件中,用重定向可就不行了。
    
    sort的-n选项:数值排序
    
    你有没有遇到过10比2小的情况。我反正遇到过。出现这种情况是由于排序程序将这些数字按字符来排序了,排序程序会先比较1和2,显然1小,所以就将10放在2前面喽。这也是sort的一贯作风。
    
    我们如果想改变这种现状,就要使用-n选项,来告诉sort,“要以数值来排序”!
    
    
    sort的-t选项和-k选项: -k选项指定按照第几列排序, -t:列与列的分隔符,分隔符两侧不同列
    
    如果有一个文件的内容是这样:
    
    

    [rocrocket@rocrocket programming]

    $ cat facebook.txt banana:30:5.5 apple:10:2.5 pear:90:2.3 orange:20:3.4 这个文件有三列,列与列之间用冒号隔开了,第一列表示水果类型,第二列表示水果数量,第三列表示水果价格。 那么我想以水果数量来排序,也就是以第二列来排序,如何利用sort实现? 幸好,sort提供了-t选项,后面可以设定间隔符。(是不是想起了cut和paste的-d选项,共鸣~~) 指定了间隔符之后,就可以用-k来指定列数了。

    [rocrocket@rocrocket programming]

    $ sort -n -k 2 -t : facebook.txt 其他的sort常用选项: -f会将小写字母都转换为大写字母来进行比较,亦即忽略大小写 -c会检查文件是否已排好序,如果乱序,则输出第一个乱序的行的相关信息,最后返回1 -C会检查文件是否已排好序,如果乱序,不输出内容,仅返回1 -M会以月份来排序,比如JAN小于FEB等等 -b会忽略每一行前面的所有空白部分,从第一个可见字符开始比较。

    grep搜索命令

    Linux grep 命令用于查找文件里符合条件的字符串。
    grep pattern file
    gerp pattern 目标文件

    -a 或 --text : 不要忽略二进制的数据。
    -A<显示行数> 或 --after-context=<显示行数> : 除了显示符合范本样式的那一列之外,并显示该行之后的内容。
    -b 或 --byte-offset : 在显示符合样式的那一行之前,标示出该行第一个字符的编号。
    -B<显示行数> 或 --before-context=<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前的内容。
    -c 或 --count : 计算符合样式的列数。
    -C<显示行数> 或 --context=<显示行数>或-<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前后的内容。
    -d <动作> 或 --directories=<动作> : 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep指令将回报信息并停止动作。
    
    -e<范本样式> 或 --regexp=<范本样式> :** 指定字符串做为查找文件内容的样式。**
    注意 -e "pattern1" -e "patttern2" 可以同时匹配多个pattern
    
    -E 或 --extended-regexp : 将样式为延伸的正则表达式来使用。
    -f<规则文件> 或 --file=<规则文件> : 指定规则文件,其内容含有一个或多个规则样式,让grep查找符合规则条件的文件内容,格式为每行一个规则样式。
    -F 或 --fixed-regexp : 将样式视为固定字符串的列表。
    -G 或 --basic-regexp : 将样式视为普通的表示法来使用。
    -h 或 --no-filename : 在显示符合样式的那一行之前,不标示该行所属的文件名称。
    -H 或 --with-filename : 在显示符合样式的那一行之前,表示该行所属的文件名称。
    -i 或 --ignore-case : 忽略字符大小写的差别。
    -l 或 --file-with-matches : 列出文件内容符合指定的样式的文件名称。
    -L 或 --files-without-match : 列出文件内容不符合指定的样式的文件名称。
    -n 或 --line-number : 在显示符合样式的那一行之前,标示出该行的列数编号。
    -o 或 --only-matching : 只显示匹配PATTERN 部分。
    -q 或 --quiet或--silent : 不显示任何信息。
    -r 或 --recursive : 此参数的效果和指定"-d recurse"参数相同。
    -s 或 --no-messages : 不显示错误信息。
    -v 或 --invert-match : 显示不包含匹配文本的所有行。
    -V 或 --version : 显示版本信息。
    -w 或 --word-regexp : 只显示全字符合的列。
    -x --line-regexp : 只显示全列符合的列。
    -y : 此参数的效果和指定"-i"参数相同。

    注意:pattern :可以有通配符

    ^ 匹配行开头
    $ 匹配行结尾
    . 匹配单个字符串
    * 匹配任意长度字符串
    [] 匹配【】中的任一个字符

    ps -ef 任务管理器

    ps -ef 查看当前所用用户的进程等详细信息

    管道 |

    在任何一个shell中,都可以使用“|”连接两个命令,shell会将前后两个进程的输入输出用一个管道相连,以便达到进程间通信的目的:
    管道本质上就是一个文件,前面的进程以写方式打开文件,后面的进程以读方式打开。这样前面写完后面读,于是就实现了通信。虽然实现形态上是文件,但是管道本身并不占用磁盘或者其他外部存储的空间。在Linux的实现上,它占用的是内存空间。所以,Linux上的管道就是一个操作方式为文件的内存缓冲区。

    重点:
    优点:相对于向硬盘中写入读取文件,|管道只会使用内存空间,因此会更加快的执行

    命令1|命令2
    管道作用就是将命令1的输出送给命令2,因此,命令2一般可以接收字符输入,上一级输出直接给下一级输入

    有些命令可以接受”标准输入”(stdin)作为参数。如果命令2 不能接受标准输入作为参数(不是文件命令),但是,大多数命令都不接受标准输入作为参数,只能直接在命令行输入参数,这导致无法用管道命令传递参数。举例来说,echo命令就不接受管道传参。可以使用xargs工具将上一级数据转换成下一级的命令的参数

    xargs命令

    作用:是将标准输入转为命令行参数。

    $ echo "hello world" | xargs echo
    hello worlds
    上面的代码将管道左侧的标准输入,转为命令行参数hello world,传给第二个echo命令。
    
    命令1| xargs 命令2

    -d 参数与分隔符
    默认情况下,xargs将换行符和空格作为分隔符,把标准输入分解成一个个命令行参数。

    $ echo "one two three" | xargs mkdir

    上面代码中,mkdir会新建三个子目录,因为xargs将one two three分解成三个命令行参数,执行mkdir one two three。

    -d参数可以更改分隔符。

    $ echo -e "a\tb\tc" | xargs -d "\t" echo
    a b c

    上面的命令指定制表符\t作为分隔符,所以a\tb\tc就转换成了三个命令行参数。echo命令的-e参数表示解释转义字符。

    使用xargs命令以后,由于存在转换参数过程,有时需要确认一下到底执行的是什么命令。

    -p参数打印出要执行的命令,询问用户是否要执行。

    $ echo 'one two three' | xargs -p touch
    touch one two three ?...

    上面的命令执行以后,会打印出最终要执行的命令,让用户确认。用户输入y以后(大小写皆可),才会真正执行。

    -t参数则是打印出最终要执行的命令,然后直接执行,不需要用户确认。

    $ echo 'one two three' | xargs -t rm
    rm one two three

    -n参数指定每次将多少项,作为命令行参数。

    $ xargs find -name
    "*.txt" "*.md"
    find: paths must precede expression: `*.md'
    上面的命令将同一行的两项作为命令行参数,导致报错。
    $ xargs -n 1 find -name

    上面命令指定将每一项(-n 1)标准输入作为命令行参数,分别执行一次命令(find -name)。

    如果xargs要将命令行参数传给多个命令,可以使用-I参数。

    -I指定每一项命令行参数的替代字符串。

    $ cat foo.txt
    one
    two
    three
    
    $ cat foo.txt | xargs -I file sh -c 'echo file; mkdir file'
    one 
    two
    three
    
    $ ls 
    one two three

    注意:上面的file是一个替代字符串,可以随便写,一般写为{},但是注意必须和后面命令对应

    命令1| xargs -I {} 命令2(将2中的部分替换为{})
    上面代码中,foo.txt是一个三行的文本文件。我们希望对每一项命令行参数,执行两个命令(echo和mkdir),使用-I file表示file是命令行参数的替代字符串。执行命令时,具体的参数会替代掉echo file; mkdir file里面的两个file。

    Linux cut命令 列截取字符串

    用于显示每行从开头算起 num1 到 num2 的文字。
    cut -c num1-num2 file 显示每一行的第num1-num2个子元

    cut -c num1,num2,num3 file 显示每一行的第num1、num2、num3 子元

    语法
    cut [-bn] [file]
    cut [-c] [file]
    cut [-df] [file]
    使用说明:

    cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。

    如果不指定 File 参数,cut 命令将读取标准输入。必须指定 -b、-c 或 -f 标志之一。

    参数:

    -b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。
    -c :以字符为单位进行分割。
    -d :自定义分隔符,默认为制表符。
    -f :与-d一起使用,指定显示哪个区域。
    -n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的
    范围之内,该字符将被写出;否则,该字符将被排除

    cut -f 1-3 file
    -f 参数用于截取第m-n栏(这里的栏值得是通过 -d分隔符确定的列,默认tab)

    例如:
    dfgf    ddg     3
    cut -f 1 file
    那么就将dfgf取出,因为是tab分割的第一栏
    
    -d
    cut -d " " -f file
    则将“ ” 空格作为分割列符

    重难点

    sed

    sed是一种流编辑器,也是文本处理中非常好的工具,配合正则使用更强大处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed命令处理缓冲区的内容,完成后输出到屏幕,接着处理下一行。文件内容并没有改变,除非使用-i选项。sed主要用来编辑一个或多个文件,简化对文件的反复操作或者用来编写转换程序等。

    sed功能同awk类似,差别在于,sed简单,对列处理的功能要差一些,awk功能复杂,对列处理的功能比较强大。
    命令格式
     sed [options] 'command' file(s)
     sed [options] -f scriptfile file(s)
    常用参数
    -e #以指定的指令来处理输入的文本文件
    -n #取消默认输出(如果和p命令同时使用只会打印发生改变的行)
    -h #帮助
    -V #显示版本信息
    常用动作
    a #在当前行下面插入文本
    i #在当前行上面插入文本
    c #把选定的行改为新的文本
    d #删除,删除选择的行
    D #删除模板块的第一行 
    s #替换指定字符
    h #拷贝模板块的内容到内存中的缓冲区
    H #追加模板块的内容到内存中的缓冲区
    g #获得内存缓冲区的内容,并替代当前模板块中的文本 
    G #获得内存缓冲区的内容,并追加到当前模板块文本的后面 
    l #列表不能打印字符的清单
    n #读取下一个输入行,用下一个命令处理新的行而不是用第一个命令
    N #追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码
    p #打印匹配的行
    P #(大写)打印模板的第一行
    q #退出Sed
    b #lable 分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾
    r #file 从file中读行
    t #label if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾
    T #label 错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾
    w #file 写并追加模板块到file末尾**
    W #file 写并追加模板块的第一行到file末尾**
    ! #表示后面的命令对所有没有被选定的行发生作用** 
    = #打印当前行号码**
    # #把注释扩展到下一个换行符以前**
    Sed替换命令
    g #表示行内全面替换(全局替换配合s命令使用)
    p #表示打印行 
    w  #表示把行写入一个文件 
    x #表示互换模板块中的文本和缓冲区中的文本 
    y #表示把一个字符翻译为另外的字符(但是不用于正则表达式) 
    1  #子串匹配标记 
    & #已匹配字符串标记
    Sed正则
    ^ #匹配行开始 
    $ #匹配行结束
    . #匹配一个非换行符的任意字符
    * #匹配0个或多个字符
    [] #匹配一个指定范围内的字符
    [^]  #匹配一个不在指定范围内的字符 
    (..) #匹配子串
    &  #保存搜索字符用来替换其他字符
    < #匹配单词的开始
    >  #匹配单词的结束
    x{m} #重复字符x,m次
    x{m,} #重复字符x,至少m次 
    x{m,n} #重复字符x,至少m次,不多于n次
    Sed常用实例
    1、替换操作
    
    echo "hello world" |sed 's/ /-/1g'
    hello-world 
    #从第一个空格开始全局替换成-,只不过文本中只有一个空格
    2、删除操作
    
    sed '/^$/d' filename #删除空白行
    sed '2d' filename #删除第二行
    sed '2,$d' filename #删除第二直到未尾所有行
    sed '$d' filename #删除最后一行
    sed '/^test/'d filename #删除以test开头行
    3、匹配替换
    
    echo "hello world" |sed 's/w+/[&]/g'
    

    [hello]

    [world] echo “hello world” |sed ‘s/w+/”&”/g’ “hello” “world” #w+匹配每一个单词,&表示匹配到的字符串 echo AAA bbb |sed ‘s/([A-Z]+) ([a-z]+)/[2] [1]/’

    [bbb]

    [AAA] #子串匹配替换 4、选定范围 sed -n ‘/= 0/,/max/p’ svnserve.conf #min-encryption = 0 #max-encryption = 256 #所有在=0到max范围内的行都会被打印出

    awk 命令

    awk是处理文本文件的一个应用程序,几乎所有 Linux 系统都自带这个程序。

    它依次处理文件的每一行,并读取里面的每一个字段。对于日志、CSV 那样的每行格式相同的文本文件,awk可能是最方便的工具。
    awk其实不仅仅是工具软件,还是一种编程语言。不过,本文只介绍它的命令行用法,对于大多数场合,应该足够用了。

    awk的基本用法就是下面的形式。

    # 格式
    $ awk 动作 文件名
    
    # 示例
    $ awk '{print $0}' demo.txt

    上面示例中,demo.txt是awk所要处理的文本文件。前面单引号内部有一个大括号,里面就是每一行的处理动作print $0。其中,print是打印命令,$0代表当前行,因此上面命令的执行结果,就是把每一行原样打印出来。

    下面,我们先用标准输入(stdin)演示上面这个例子。

    $ echo 'this is a test' | awk '{print $0}'
    this is a test

    上面代码中,print $0就是把标准输入this is a test,重新打印了一遍。

    awk会根据空格和制表符,将每一行分成若干字段,依次用$1、$2、$3代表第一个字段、第二个字段、第三个字段等等。

    $ echo 'this is a test' | awk '{print $3}'
    a
    上面代码中,$3代表this is a test的第三个字段a。

    awk允许指定输出条件,只输出符合条件的行。

    输出条件要写在动作的前面。

    $ awk '条件 动作' 文件名

    请看下面的例子。

    $ awk -F ':' '/usr/ {print $1}' demo.txt
    root
    daemon
    bin
    sys

    上面代码中,print命令前面是一个正则表达式,只输出包含usr的行。

    下面的例子只输出奇数行,以及输出第三行以后的行。

    linux命令

    ps -ef 任务管理器

    ps -ef

    tr :traanslate 用于转换或者删除文件中的字符

    Linux tr 命令用于转换或删除文件中的字符。

    tr 指令从标准输入设备读取数据,经过字符串转译后,将结果输出到标准输出设备。

    tr [-cdst][--help][--version][第一字符集][第二字符集]  
    tr [OPTION]…SET1[SET2] 
    参数说明:
    
    -c, --complement:反选设定字符。也就是符合 SET1 的部份不做处理,不符合的剩余部份才进行转换
    -d, --delete:删除指令字符
    -s, --squeeze-repeats:缩减连续重复的字符成指定的单个字符
    -t, --truncate-set1:削减 SET1 指定范围,使之与 SET2 设定长度相等
    --help:显示程序用法信息
    --version:显示程序本身的版本信息
    字符集合的范围:
    
    \NNN 八进制值的字符 NNN (1 to 3 为八进制值的字符)
    \\ 反斜杠
    \a Ctrl-G 铃声
    \b Ctrl-H 退格符
    \f Ctrl-L 走行换页
    \n Ctrl-J 新行
    \r Ctrl-M 回车
    \t Ctrl-I tab键
    \v Ctrl-X 水平制表符
    CHAR1-CHAR2 :字符范围从 CHAR1 到 CHAR2 的指定,范围的指定以 ASCII 码的次序为基础,只能由小到大,不能由大到小。
    [CHAR*] :这是 SET2 专用的设定,功能是重复指定的字符到与 SET1 相同长度为止
    [CHAR*REPEAT] :这也是 SET2 专用的设定,功能是重复指定的字符到设定的 REPEAT 次数为止(REPEAT 的数字采 8 进位制计算,以 0 为开始)
    [:alnum:] :所有字母字符与数字
    [:alpha:] :所有字母字符
    [:blank:] :所有水平空格
    [:cntrl:] :所有控制字符
    [:digit:] :所有数字
    [:graph:] :所有可打印的字符(不包含空格符)
    [:lower:] :所有小写字母
    [:print:] :所有可打印的字符(包含空格符)
    [:punct:] :所有标点字符
    [:space:] :所有水平与垂直空格符
    [:upper:] :所有大写字母
    [:xdigit:] :所有 16 进位制的数字
    [=CHAR=] :所有符合指定的字符(等号里的 CHAR,代表你可自订的字符)

    实例

    将文件testfile中的小写字母全部转换成大写字母,此时,可使用如下命令:

    cat testfile |tr a-z A-Z

    实例:

    cat filename | tr [:lower:] [:upper:] 转换大小写 ,|管道命令
    cat filename | tr a-z A-Z >newfile 
    
    使用tr删除字符:
    echo "hello 123 world 456" | tr -d '0-9'
    hello  world 
    
    将制表符转换为空格:
    cat text | tr '\t' ' '
    
    用tr压缩字符,可以压缩输入中重复的字符:
    echo "thissss is      a text linnnnnnne." | tr -s ' sn'
    this is a text line.

    tee命令基于标准输入读取数据,标准输出或文件写入数据

    tee [-ai][--help][--version][文件...]

    参数:

    -a或--append  附加到既有文件的后面,而非覆盖它.
    -i或--ignore-interrupts  忽略中断信号。
    --help  在线帮助。
    --version  显示版本信息。

    $ tee file1 file2 #在两个文件中复制内容

    md5sum 命令;验证网络文件传输的完整性

    MD5算法常常被用来验证网络文件传输的完整性,防止文件被人篡改。MD5 全称是报文摘要算法(Message-Digest Algorithm 5),此算法对任意长度的信息逐位进行计算,产生一个二进制长度为128位(十六进制长度就是32位)的“指纹”(或称“报文摘要”),不同的文件产生相同的报文摘要的可能性是非常非常之小的。
    在Linux或Unix上,md5sum是用来计算和校验文件报文摘要的工具程序。一般来说,安装了Linux后,就会有md5sum这个工具,直接在命令行终端直接运行。、

    命令格式

    md5sum [OPTION]... [FILE]...

    3、命令选项

    -b 或 --binary :把输入文件作为二进制文件看待。 
    -t 或 --text :把输入的文件作为文本文件看待(默认)。 
    -c 或 --check :用来从文件中读取md5信息检查文件的一致性。(不细说了参见info) 
    --status :这个选项和check一起使用,在check的时候,不输出,而是根据返回值表示检查结果。 
    -w 或 --warn :在check的时候,检查输入的md5信息又没有非法的行,如果有则输出相应信息。
    
    文件FILE:指定保存着文件名和校验和的文本文件
    查看一个文件的md5值
     md5sum 文件名
    
    生产这个个文件的md5值
    

    [root@web-master ~]

    # md5sum kevin.sql > kevin.sql.md5 检查两个文件是否一样,可以通过比较两个文件的md5值 (后续可以用这个方法来检验kevin.sql文件是否被修改)。

    [root@web-master ~]

    # md5sum kevin.sql 170ecb8475ca6e384dbd74c17e165c9e kevin.sql

    [root@web-master ~]

    # cat kevin.sql.md5 170ecb8475ca6e384dbd74c17e165c9e kevin.sql

    linux系列

    tar 解压命令

    Linux tar(英文全拼:tape archive )命令用于备份文件。

    tar 是用来建立,还原备份文件的工具程序,它可以加入,解开备份文件内的文件。

    -c 压缩文件 -x解压文件 -f<备份文件>或–file=<备份文件> 指定备份文件。

    tar [-ABcdgGhiklmMoOpPrRsStuUvwWxzZ][-b <区块数目>][-C <目的目录>][-f <备份文件>][-F <Script文件>][-K <文件>][-L <媒体容量>][-N <日期时间>][-T <范本文件>][-V <卷册名称>][-X <范本文件>][-<设备编号><存储密度>][--after-date=<日期时间>][--atime-preserve][--backuup=<备份方式>][--checkpoint][--concatenate][--confirmation][--delete][--exclude=<范本样式>][--force-local][--group=<群组名称>][--help][--ignore-failed-read][--new-volume-script=<Script文件>][--newer-mtime][--no-recursion][--null][--numeric-owner][--owner=<用户名称>][--posix][--erve][--preserve-order][--preserve-permissions][--record-size=<区块数目>][--recursive-unlink][--remove-files][--rsh-command=<执行指令>][--same-owner][--suffix=<备份字尾字符串>][--totals][--use-compress-program=<执行指令>][--version][--volno-file=<编号文件>][文件或目录...]
    参数:
    
    -A或--catenate 新增文件到已存在的备份文件。
    -b<区块数目>或--blocking-factor=<区块数目> 设置每笔记录的区块数目,每个区块大小为12Bytes。
    -B或--read-full-records 读取数据时重设区块大小。
    -c或--create 建立新的备份文件。
    -C<目的目录>或--directory=<目的目录> 切换到指定的目录。
    -d或--diff或--compare 对比备份文件内和文件系统上的文件的差异。
    -f<备份文件>或--file=<备份文件> 指定备份文件。
    -F<Script文件>或--info-script=<Script文件> 每次更换磁带时,就执行指定的Script文件。
    -g或--listed-incremental 处理GNU格式的大量备份。
    -G或--incremental 处理旧的GNU格式的大量备份。
    -h或--dereference 不建立符号连接,直接复制该连接所指向的原始文件。
    -i或--ignore-zeros 忽略备份文件中的0 Byte区块,也就是EOF。
    -k或--keep-old-files 解开备份文件时,不覆盖已有的文件。
    -K<文件>或--starting-file=<文件> 从指定的文件开始还原。
    -l或--one-file-system 复制的文件或目录存放的文件系统,必须与tar指令执行时所处的文件系统相同,否则不予复制。
    -L<媒体容量>或-tape-length=<媒体容量> 设置存放每体的容量,单位以1024 Bytes计算。
    -m或--modification-time 还原文件时,不变更文件的更改时间。
    -M或--multi-volume 在建立,还原备份文件或列出其中的内容时,采用多卷册模式。
    -N<日期格式>或--newer=<日期时间> 只将较指定日期更新的文件保存到备份文件里。
    -o或--old-archive或--portability 将资料写入备份文件时使用V7格式。
    -O或--stdout 把从备份文件里还原的文件输出到标准输出设备。
    -p或--same-permissions 用原来的文件权限还原文件。
    -P或--absolute-names 文件名使用绝对名称,不移除文件名称前的"/"号。
    -r或--append 新增文件到已存在的备份文件的结尾部分。
    -R或--block-number 列出每个信息在备份文件中的区块编号。
    -s或--same-order 还原文件的顺序和备份文件内的存放顺序相同。
    -S或--sparse 倘若一个文件内含大量的连续0字节,则将此文件存成稀疏文件。
    -t或--list 列出备份文件的内容。
    -T<范本文件>或--files-from=<范本文件> 指定范本文件,其内含有一个或多个范本样式,让tar解开或建立符合设置条件的文件。
    -u或--update 仅置换较备份文件内的文件更新的文件。
    -U或--unlink-first 解开压缩文件还原文件之前,先解除文件的连接。
    -v或--verbose 显示指令执行过程。
    -V<卷册名称>或--label=<卷册名称> 建立使用指定的卷册名称的备份文件。
    -w或--interactive 遭遇问题时先询问用户。
    -W或--verify 写入备份文件后,确认文件正确无误。
    -x或--extract或--get 从备份文件中还原文件。
    -X<范本文件>或--exclude-from=<范本文件> 指定范本文件,其内含有一个或多个范本样式,让ar排除符合设置条件的文件。
    -z或--gzip或--ungzip 通过gzip指令处理备份文件。
    -Z或--compress或--uncompress 通过compress指令处理备份文件。
    -<设备编号><存储密度> 设置备份用的外围设备编号及存放数据的密度。
    --after-date=<日期时间> 此参数的效果和指定"-N"参数相同。
    --atime-preserve 不变更文件的存取时间。
    --backup=<备份方式>或--backup 移除文件前先进行备份。
    --checkpoint 读取备份文件时列出目录名称。
    --concatenate 此参数的效果和指定"-A"参数相同。
    --confirmation 此参数的效果和指定"-w"参数相同。
    --delete 从备份文件中删除指定的文件。
    --exclude=<范本样式> 排除符合范本样式的文件。
    --group=<群组名称> 把加入设备文件中的文件的所属群组设成指定的群组。
    --help 在线帮助。
    --ignore-failed-read 忽略数据读取错误,不中断程序的执行。
    --new-volume-script=<Script文件> 此参数的效果和指定"-F"参数相同。
    --newer-mtime 只保存更改过的文件。
    --no-recursion 不做递归处理,也就是指定目录下的所有文件及子目录不予处理。
    --null 从null设备读取文件名称。
    --numeric-owner 以用户识别码及群组识别码取代用户名称和群组名称。
    --owner=<用户名称> 把加入备份文件中的文件的拥有者设成指定的用户。
    --posix 将数据写入备份文件时使用POSIX格式。
    --preserve 此参数的效果和指定"-ps"参数相同。
    --preserve-order 此参数的效果和指定"-A"参数相同。
    --preserve-permissions 此参数的效果和指定"-p"参数相同。
    --record-size=<区块数目> 此参数的效果和指定"-b"参数相同。
    --recursive-unlink 解开压缩文件还原目录之前,先解除整个目录下所有文件的连接。
    --remove-files 文件加入备份文件后,就将其删除。
    --rsh-command=<执行指令> 设置要在远端主机上执行的指令,以取代rsh指令。
    --same-owner 尝试以相同的文件拥有者还原文件。
    --suffix=<备份字尾字符串> 移除文件前先行备份。
    --totals 备份文件建立后,列出文件大小。
    --use-compress-program=<执行指令> 通过指定的指令处理备份文件。
    --version 显示版本信息。
    --volno-file=<编号文件> 使用指定文件内的编号取代预设的卷册编号。

    实例
    压缩文件 非打包

    # touch a.c     
    # tar -czvf test.tar.gz a.c   //压缩 a.c文件为test.tar.gz
    a.c
    
    列出压缩文件内容
    
    # tar -tzvf test.tar.gz 
    -rw-r--r-- root/root     0 2010-05-24 16:51:59 a.c
    解压文件
    
    # tar -xzvf test.tar.gz 
    a.c

    bash 脚本语法

    以下内容参:
    https://wangdoc.com/bash/intro.html

    bash中的特殊变量

    $ $ 当前进程ID
    
    $? 上一个命令的退出码,用来判断上一个命令是否执行成功。返回值是0,表示上一个命令执行成功;如果不是零,表示上一个命令执行失败。
    
    $_为上一个命令的最后一个参数。
    
    $!
    
    $!为最近一个后台执行的异步命令的进程 ID。
    
    $0为当前 Shell 的名称(在命令行直接执行时)或者脚本名(在脚本中执行时)。
    $-为当前 Shell 的启动参数。
    $#表示脚本的参数数量,$@表示脚本的参数值

    read命令:向脚本中读取用户输入

    有时,脚本需要在执行过程中,由用户提供一部分数据,这时可以使用read命令。它将用户的输入存入一个变量,方便后面的代码使用。用户按下回车键,就表示输入结束。

    read命令的格式如下:

    read [-options] [variable...]

    上面语法中,options是参数选项,variable是用来保存输入数值的一个或多个变量名。如果没有提供变量名,环境变量REPLY会包含用户输入的一整行数据。

    read可以接受用户输入的多个值。

    #!/bin/bash
    
    echo -n "输入一些文本 > "
    read text
    echo "你的输入:$text"

    如果用户的输入项少于read命令给出的变量数目,那么额外的变量值为空。如果用户的输入项多于定义的变量,那么多余的输入项会包含到最后一个变量中。

    #!/bin/bash
    echo Please, enter your firstname and lastname
    read FN LN
    echo "Hi! $LN, $FN !"

    如果read命令之后没有定义变量名,那么环境变量REPLY会包含所有的输入。

    #!/bin/bash
    # read-single: read multiple values into default variable
    echo -n "Enter one or more values > "
    read
    echo "REPLY = '$REPLY'"

    read命令的参数如下。

    -t :设置超时的秒数,如果用户超过这个时间没有输入,这个命令就会执行失败
    -p :设置用户输入的提示信息
    
    -a :把用户的 输入赋值给一个数组,从零号位置开始
    
    例如:
    $ read -a people
    alice duchess dodo
    $ echo ${people[2]}
    dodo
    
    -n参数指定只读取若干个字符作为变量值,而不是整行读取。
    $ read -n 3 letter
    abcdefghij
    $ echo $letter
    abc
    
    -e参数允许用户输入的时候,使用readline库提供的快捷键,比如自动补全。

    串行执行程序 && ||

    cmd1 && cmd2 :如果cmd1成功执行,才执行cmd2.如果cmd1失败,那么cmd2不会执行
    
    cmd1 || cmd2 :如果cmd1执行失败才执行cmd2,否则不执行cmd2

    test 判断的逻辑运算 用于 if 语句

    if关键字后面,跟的是一个命令。这个命令可以是test命令,也可以是其他命令。命令的返回值为0表示判断成立,否则表示不成立。因为这些命令主要是为了得到返回值,所以可以视为表达式。
    格式:

    test expression  or [expression]
    
    
    expression:下面的都是[expresson],如果使用 test  ,则不需要加上 【】
    
    1、文件 表达式
    
    [ -a file ]:如果 file 存在,则为true。
    [ -b file ]:如果 file 存在并且是一个块(设备)文件,则为true。
    [ -c file ]:如果 file 存在并且是一个字符(设备)文件,则为true。
    [ -d file ]:如果 file 存在并且是一个目录,则为true。
    [ -e file ]:如果 file 存在,则为true。
    [ -f file ]:如果 file 存在并且是一个普通文件,则为true。
    [ -g file ]:如果 file 存在并且设置了组 ID,则为true。
    [ -G file ]:如果 file 存在并且属于有效的组 ID,则为true。
    [ -h file ]:如果 file 存在并且是符号链接,则为true。
    [ -k file ]:如果 file 存在并且设置了它的“sticky bit”,则为true。
    [ -L file ]:如果 file 存在并且是一个符号链接,则为true。
    [ -N file ]:如果 file 存在并且自上次读取后已被修改,则为true。
    [ -O file ]:如果 file 存在并且属于有效的用户 ID,则为true。
    [ -p file ]:如果 file 存在并且是一个命名管道,则为true。
    [ -r file ]:如果 file 存在并且可读(当前用户有可读权限),则为true。
    [ -s file ]:如果 file 存在且其长度大于零,则为true。
    [ -S file ]:如果 file 存在且是一个网络 socket,则为true。
    [ -t fd ]:如果 fd 是一个文件描述符,并且重定向到终端,则为true。 这可以用来判断是否重定向了标准输入/输出/错误。
    [ -u file ]:如果 file 存在并且设置了 setuid 位,则为true。
    [ -w file ]:如果 file 存在并且可写(当前用户拥有可写权限),则为true。
    [ -x file ]:如果 file 存在并且可执行(有效用户有执行/搜索权限),则为true。
    [ file1 -nt file2 ]:如果 FILE1 比 FILE2 的更新时间最近,或者 FILE1 存在而 FILE2 不存在,则为true。
    [ file1 -ot file2 ]:如果 FILE1 比 FILE2 的更新时间更旧,或者 FILE2 存在而 FILE1 不存在,则为true。
    [ FILE1 -ef FILE2 ]:如果 FILE1 和 FILE2 引用相同的设备和 inode 编号,则为true。
    2、number 表达式
    
    下面的表达式用于判断整数。
    
    [ integer1 -eq integer2 ]:如果integer1等于integer2,则为true。
    [ integer1 -ne integer2 ]:如果integer1不等于integer2,则为true。
    [ integer1 -le integer2 ]:如果integer1小于或等于integer2,则为true。
    [ integer1 -lt integer2 ]:如果integer1小于integer2,则为true。
    [ integer1 -ge integer2 ]:如果integer1大于或等于integer2,则为true。
    [ integer1 -gt integer2 ]:如果integer1大于integer2,则为true。
    3、字符串表达式:
    以下表达式用来判断字符串。
    
    [ string ]:如果string不为空(长度大于0),则判断为真。
    [ -n string ]:如果字符串string的长度大于零,则判断为真。
    [ -z string ]:如果字符串string的长度为零,则判断为真。
    [ string1 = string2 ]:如果string1和string2相同,则判断为真。
    [ string1 == string2 ] 等同于[ string1 = string2 ]。
    [ string1 != string2 ]:如果string1和string2不相同,则判断为真。
    [ string1 '>' string2 ]:如果按照字典顺序string1排列在string2之后,则判断为真。
    [ string1 '<' string2 ]:如果按照字典顺序string1排列在string2之前,则判断为真。
    
    test命令内部的>和<,必须用引号引起来(或者是用反斜杠转义)。否则,它们会被 shell 解释为重定向操作符。

    通过逻辑运算,可以把多个test判断表达式结合起来,创造更复杂的判断。三种逻辑运算AND,OR,和NOT,都有自己的专用符号。

    AND运算:符号&&,也可使用参数-a。
    OR运算:符号||,也可使用参数-o。
    NOT运算:符号!。
    test expression1&&expression2

    例如:
    #!/bin/bash
    
    MIN_VAL=1
    MAX_VAL=100
    
    INT=50
    
    if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
      if [[ $INT -ge $MIN_VAL && $INT -le $MAX_VAL ]]; then
        echo "$INT is within $MIN_VAL to $MAX_VAL."
      else
        echo "$INT is out of range."
      fi
    else
      echo "INT is not an integer." >&2
      exit 1
    fi

    shell

    串行执行程序 && ||

    1. command1 ; commond2 执行完1在执行2
    2. commond1 && commond2 如果cmd1执行成功($?=0),则开始执行cmd2,如果cmd1执行错误($?=1),则不执行cmd2
    3. cmd1 || cmd2 如果cmd1执行错误($?=1),才执行cmd2 ,否则不执行cmd2

    test命令

    在11.15课程总结部分已经给出,这里就不再赘述。

    exit()命令

    exit 退出当前shell
    Linux exit命令用于退出目前的shell。
    执行exit可使shell以指定的状态值退出。若不设置状态值参数,则shell以预设值退出。状态值0代表执行成功,其他值代表执行失败。exit也可用在script,离开正在执行的script,回到shell。
    0    执行成功
    1    执行失败
    $?    参照上一个状态值

    linux脚本: if语句

    if [expression] then;
        comd
    elif [expression] then ;
        commd
    else 
        commd
    fi
    if和then写在同一行时,需要分号分隔。分号是 Bash 的命令分隔符。它们也可以写成两行,这时不需要分号。
    
    Bash 还提供了((...))作为算术条件,进行算术运算的判断。
    
    if ((3 > 2)); then
      echo "true"
    fi

    case结构

    case结构用于多值判断,可以为每个值指定对应的命令,跟包含多个elif的if结构等价,但是语义更好。它的语法如下。

    case expression in
      pattern1 )
        commands ;;
      pattern2 )
        commands ;;
      pattern3 )
        commands ;;
      *) 
        commands ;;
    最后一条匹配语句的模式是*,这个通配符可以匹配其他字符和没有输入字符的情况,类似if的else部分
      ...
    esac

    例子:

    echo -n "输入一个1到3之间的数字(包含两端)> "
    read character
    case $character in
      1 ) echo 1
        ;;
      2 ) echo 2
        ;;
      3 ) echo 3
        ;;
      * ) echo 输入不符合要求
    esac

    while 循环

    while循环有一个判断条件,只要符合条件,就不断循环执行指定的语句。

    while condition; do
      commands
    done

    上面代码中,只要满足条件condition,就会执行命令commands。然后,再次判断是否满足条件condition,只要满足,就会一直执行下去。只有不满足条件,才会退出循环。
    循环条件condition可以使用test命令,跟if结构的判断条件写法一致。

    while true
    do
      echo 'Hi, while looping ...';
    done

    for 循环

    for…in 循环
    for…in循环用于遍历列表的每一项。

    for variable in list
    do
      commands
    done

    上面语法中,for循环会依次从list列表中取出一项,作为变量variable,然后在循环体中进行处理。

    关键词do可以跟for写在同一行,两者使用分号分隔。

    for i in word1 word2 word3; do
      echo $i
    done

    for循环还支持 C 语言的循环语法。

    for (( expression1; expression2; expression3 )); do
      commands
    done

    break,continue

    Bash 提供了两个内部命令break和continue,用来在循环内部跳出循环。
    break命令立即终止循环,程序继续执行循环块之后的语句,即不再执行剩下的循环。

    select 结构

    select结构主要用来生成简单的菜单。它的语法与for…in循环基本一致。

    select name
    

    [in list]

    do commands done

    Bash 会对select依次进行下面的处理。
    select生成一个菜单,内容是列表list的每一项,并且每一项前面还有一个数字编号。
    Bash 提示用户选择一项,输入它的编号。
    用户输入以后,Bash 会将该项的内容存在变量name,该项的编号存入环境变量REPLY。如果用户没有输入,就按回车键,Bash 会重新输出菜单,让用户选择。
    执行命令体commands。
    执行结束后,回到第一步,重复这个过程。

    let 命令

    let命令声明变量时,可以直接执行算术表达式。

    $ let foo=1+2
    $ echo $foo
    3

    上面例子中,let命令可以直接计算1 + 2。

    let命令的参数表达式如果包含空格,就需要使用引号。

    $ let "foo = 1 + 2"

    let可以同时对多个变量赋值,赋值表达式之间使用空格分隔。

    $ let "v1 = 1" "v2 = v1++"
    $ echo $v1,$v2
    2,1

    上面例子中,let声明了两个变量v1和v2,其中v2等于v1++,表示先返回v1的值,然后v1自增。

    expr 计算器

    expr命令是一个手工命令行计数器,用于在UNIX/LINUX下求表达式变量的值,一般用于整数值,也可用于字符串。

    expr 表达式
    表达式说明:

    用空格隔开每个项;
    用反斜杠 \ 放在 shell 特定的字符前面; "\*"
    对包含空格和其他特殊字符的字符串要用引号括起来
     > expr 14 % 9
     5
     > expr 10 + 10
     20
     > expr 1000 + 900
     1900
     > expr 30 / 3 / 2
     5
     > expr 30 \* 3 (使用乘号时,必须用反斜线屏蔽其特定含义。因为shell可能会误解显示星号的意义)
     90
     > expr 30 * 3
     expr: Syntax error

    $[] 计算

    Shell $[] 的用法如下:

    $[表达式]
    $[5+3]
    $[] 会对表达式进行计算,并取得计算结果。如果表达式中包含了变量,那么你可以加$,也可以不加。

    bc 命令

    bc是任意精度计算器语言,通常在linux下当计算器用。

    它类似基本的计算器, 使用这个计算器可以做基本的数学运算。
    常用的运算:

    + 加法
    - 减法
    * 乘法
    / 除法
    ^ 指数
    % 余数
    实例:
    通过管道符
    
    $ echo "15+5" | bc
    20
    
    $ echo 'scale=2; (2.777 - 1.4744)/1' | bc
    1.30
    
    $ echo "10^10" | bc 
    10000000000
    
    $ echo "sqrt(100)" | bc
    10