grep 是 Linux 系统中非常强大且常用的命令行工具,用于在文件中搜索指定的字符串或正则表达式。其名称来自 "global regular expression print",意思是全局正则表达式打印。

基本语法:

grep [选项] '模式' 文件名

常用选项:

选项说明
-i忽略大小写
-v反向匹配,显示不包含匹配内容的行
-r-R递归搜索目录中的所有文件
-n显示匹配行的行号
-l只列出包含匹配内容的文件名
-c统计匹配的行数
--color=auto高亮显示匹配的部分(大多数 Linux 发行版默认启用)

使用示例:

  1. 在文件中查找字符串

    grep "hello" file.txt

    查找 file.txt 文件中包含 "hello" 的行。

  2. 忽略大小写

    grep -i "hello" file.txt
  3. 查找不包含某字符串的行

    grep -v "error" log.txt
  4. 递归查找目录中匹配内容

    grep -r "main" ./src
  5. 查找支持正则表达式

    grep "^start" file.txt

    匹配以 "start" 开头的行。


小技巧:

  • 可以与 pipe (|) 命令结合使用,从其他命令的输出中筛选信息:

    dmesg | grep usb
  • 与正则表达式配合,处理文本非常灵活。

grep -q

grep -qgrep 命令的一个非常实用的选项,意思是 安静模式(quiet / silent),它不会输出任何匹配结果,只通过返回码(退出状态码)来表示是否匹配成功。


✅ 功能说明:

  • 当使用 q 选项时,grep 不会在终端显示任何匹配的文本。
  • 仅通过退出码来判断是否有匹配行

🔢 退出状态码说明:

退出码含义
0找到匹配项
1未找到匹配项
2出现错误(如文件不存在等)

🧪 使用示例:

  1. 判断一个文件是否包含某个字符串:

    if grep -q "error" log.txt; then
        echo "日志中包含错误"
    else
        echo "日志中未发现错误"
    fi
    
  2. 配合 &&|| 使用:

    grep -q "success" result.txt && echo "任务成功"
    grep -q "fail" result.txt || echo "任务未失败"

使用 Cookies 存储和获取 Access Token 和 Refresh Token 是一种相对安全的做法,尤其是当你设置了 HttpOnly 标志时,这样可以防止 JavaScript 访问这些 Cookies,从而降低 XSS 攻击的风险。以下是如何在 React 中存储和获取 Cookies 的示例。

1. 安装 js-cookie

为了更方便地处理 Cookies,可以使用 js-cookie 库。首先,需要安装它:

npm install js-cookie

2. 示例代码

下面是如何使用 js-cookie 进行存储和获取 Cookies 的示例。

存储令牌

当你从登录 API 获取 Access Token 和 Refresh Token 后,可以使用 Cookies.set 来存储它们。

import Cookies from 'js-cookie';

// 假设你在登录成功时得到了这两个令牌
const accessToken = 'your_access_token';
const refreshToken = 'your_refresh_token';

// 存储 Cookies
Cookies.set('accessToken', accessToken, { expires: 7, secure: true, sameSite: 'Strict' }); // 7天过期
Cookies.set('refreshToken', refreshToken, { expires: 30, secure: true, sameSite: 'Strict' }); // 30天过期

在上面的代码中,expires 参数设置了 Cookies 的过期时间,secure 参数表示只有在 HTTPS 协议下才能发送 Cookies,sameSite 限制了 Cookies 在一定情况下的使用。

获取令牌

在需要访问令牌时,可以通过 Cookies.get 进行获取。

import Cookies from 'js-cookie';

// 获取令牌
const accessToken = Cookies.get('accessToken');
const refreshToken = Cookies.get('refreshToken');

// 使用令牌
if (accessToken) {
    console.log('Access Token:', accessToken);
}
if (refreshToken) {
    console.log('Refresh Token:', refreshToken);
}

3. 应用 Cookies 的情况

当你在发起API请求时,需要在请求头中附带 Access Token,可以通过上述方式获取它:

import axios from 'axios';
import Cookies from 'js-cookie';

// 创建一个 Axios 实例
const api = axios.create({
    baseURL: '<http://your-api-endpoint.com>',
});

// 添加请求拦截器
api.interceptors.request.use(
    config => {
        const token = Cookies.get('accessToken');
        if (token) {
            config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
    },
    error => {
        return Promise.reject(error);
    }
);

// 示例 API 调用
const fetchData = async () => {
    try {
        const response = await api.get('/protected-resource');
        console.log(response.data);
    } catch (error) {
        console.error(error);
    }
};

// 调用 fetchData
fetchData();

4. 注意事项

  • HttpOnly Cookies:如果你将 Cookies 设置为 HttpOnly,JavaScript 将无法访问这些 Cookies,因此你需要在服务器端设置 Cookies,并通过 set-cookie 响应头发送给客户端。
  • Cross-Origin Resource Sharing (CORS):如果你的 API 在不同的域上,要确保 CORS 设置正确,以允许 cookies 传递。
  • Secure Flag:在生产环境中部署时,请确保你的应用使用 HTTPS,并且在存储 Cookies 时设置 secure 标志,使 Cookies 只能通过安全的连接传输。

通过这种方式,可以安全地存储和获取 Access Token 和 Refresh Token, 提高应用的安全性。

在 React Bootstrap 中,spanorderoffset 这三个参数用于定义网格布局中的列(Col)的行为:

  1. span: 这个参数指定了列应该占用的模板列的数量。例如,span: 6 意味着该列将在一个12列的网格中占用6列。这样可以灵活地控制列的宽度和布局。
  2. order: 这个参数用于控制内容的视觉顺序。通过设置该参数,可以改变列在页面上显示的顺序,而不仅仅是它们在代码中的顺序。例如,order: 1order: 2 可以改变两个列的排列顺序,即使它们在代码中声明的顺序是相反的。
  3. offset: 这个参数用于生成列的偏移量,即在某一列前留出的空白列数。例如,offset: 2 将在该列前面留出2列的空白,允许创建更加灵活的布局。

下面给出两种常见的做法,关键在于如何统计某个标签被多少篇文章引用:

方法一:使用 Join Table 直接查询统计

假设你的多对多关系存储在 article_tags 表中,并且标签模型(Tag)类似如下:

type Tag struct {
    ID   uint   `gorm:"primaryKey"`
    Name string
    // 其他字段...
}

那么在删除文章时,你可以通过查询 article_tags 表来统计当前标签是否被其他文章引用:

func DeletePost(uid string) error {
    var article Article
    db := sql.GetDB()

    // 预加载 Tags, 这样后续能遍历对应的标签
    if err := db.Where("uid = ?", uid).Preload("Tags").First(&article).Error; err != nil {
        return err
    }
    
    // 遍历每个标签,检查是否还存在其他文章关联
    for _, tag := range article.Tags {
        var count int64
        // 查询 join table 中该 tag 被其他文章引用的次数
        // 请确保 "article_tags" 为你实际使用的表名
        db.Table("article_tags").Where("tag_id = ?", tag.ID).Count(&count)
        if count == 1 {
            // 如果仅有一个关联,则删除该标签
            if err := db.Delete(&tag).Error; err != nil {
                return err
            }
        }
    }

    // 移除关联(删除 join table 中对应记录)
    if err := db.Model(&article).Association("Tags").Clear(); err != nil {
        return err
    }

    // 删除文章记录
    if err := db.Delete(&article).Error; err != nil {
        return err
    }
    return nil
}

方法二:借助 GORM Association Mode 的 Count 方法

如果你在标签的模型中也定义了与文章的关联(比如在 Tag 模型中加入 Articles []Article gorm:"many2many:article_tags;"`),你就可以利用 GORM 内置的 Association("Articles").Count()` 来查询关联数量。示例如下:

标签模型:

type Tag struct {
    ID       uint      `gorm:"primaryKey"`
    Name     string
    Articles []Article `gorm:"many2many:article_tags;"`
}

在删除文章的函数中:

func DeletePost(uid string) error {
    var article Article
    db := sql.GetDB()

    // 预加载 Tags,确保能遍历所有标签
    if err := db.Where("uid = ?", uid).Preload("Tags").First(&article).Error; err != nil {
        return err
    }

    // 先清除文章与标签的关联关系
    if err := db.Model(&article).Association("Tags").Clear(); err != nil {
        return err
    }

        // 检查每个标签是否已经没有文章关联,如果是则删除标签
    for _, tag := range article.Tags {
        // 使用 Association Mode 的 Count 方法
        count := db.Model(&tag).Association("Articles").Count()
        if count == 1 {
            if err := db.Delete(&tag).Error; err != nil {
                return err
            }
        }
    }
    
    // 删除文章记录
    if err := db.Delete(&article).Error; err != nil {
        return err
    }
    return nil
}

总结

  • 查询统计方式:可以直接根据 join table(如 article_tags)进行查询统计,代码简单直观,不需要在 Tag 模型中额外定义关联。
  • Association Count 方式:需要在 Tag 模型中定义反向的多对多关联,但借助 GORM 的 Association().Count() 方法,代码更加面向对象,调用简单。

两种方法各有优劣,可以根据你的项目情况(模型定义是否包含双向关联、代码风格偏好等)来选择。