普通视图

发现新文章,点击刷新页面。
昨天以前首页

Mac 命令行及 Linux 使用指南与示例

2025年3月30日 21:30

通用基础命令(Mac 和 Linux 均适用)

1. 文件与目录操作

命令 功能说明 示例
ls 列出目录内容 ls -al(显示所有文件,包括隐藏文件)
cd 切换目录 cd ~/Documents(进入用户文档目录)
pwd 显示当前目录路径 pwd
cp 复制文件或目录 cp file.txt backup/
mv 移动或重命名文件 mv old.txt new.txt
rm 删除文件或目录 rm -rf dir/(强制递归删除目录)
mkdir 创建目录 mkdir project
touch 创建空文件 touch newfile.txt

2. 文本操作与处理

命令 功能说明 示例
cat 查看文件内容 cat log.txt
grep 文本搜索 grep "error" /var/log/syslog
echo 输出内容或写入文件 echo "Hello" > hello.txt
nano / vim 文本编辑器 vim notes.md
head / tail 查看文件头/尾部内容 tail -f log.txt(实时追踪日志)

3. 系统信息与进程管理

命令 功能说明 示例
ps 查看进程信息 ps aux | grep chrome
top / htop 实时监控系统资源 htop(需安装)
kill 终止进程 kill -9 1234(强制终止 PID 1234 的进程)
df / du 查看磁盘使用情况 df -h(以易读格式显示磁盘空间)
free 查看内存使用(Linux) free -m(显示内存以 MB 为单位)

Mac 特有命令与工具

1. 系统信息与管理

命令/工具 功能说明 示例
sw_vers 查看 macOS 版本 sw_vers -productVersion
system_profiler 查看硬件和系统信息 system_profiler SPHardwareDataType
open 用默认程序打开文件或目录 open .(在 Finder 中打开当前目录)
pbcopy / pbpaste 剪贴板操作 cat file.txt | pbcopy(复制文件内容到剪贴板)

2. 包管理工具:Homebrew

# 安装 Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 常用操作
brew install wget     # 安装软件
brew update           # 更新包列表
brew upgrade          # 升级所有已安装包
brew remove node      # 卸载软件

Linux 特有命令与工具

1. 包管理(Debian/Ubuntu)

# 更新与安装
sudo apt update        # 更新软件源
sudo apt install nginx # 安装软件
sudo apt remove nginx  # 卸载软件
sudo apt autoremove    # 清理无用依赖

# 查看已安装软件
apt list --installed

2. 系统服务管理(Systemd)

sudo systemctl start nginx    # 启动服务
sudo systemctl stop nginx     # 停止服务
sudo systemctl restart nginx  # 重启服务
sudo systemctl status nginx   # 查看服务状态

3. 网络工具

# 查看 IP 地址(Linux)
ip addr show

# 测试网络连通性
ping google.com

# 查看开放端口
netstat -tuln

Mac 与 Linux 的差异点

1. 命令参数差异

功能 Mac(BSD 风格) Linux(GNU 风格)
查看文件修改时间 ls -lT ls -l --time-style=full-iso
文本替换(sed) sed -i '' 's/old/new/g' file sed -i 's/old/new/g' file
计算 MD5 校验和 md5 file.txt md5sum file.txt

2. 文件系统路径差异

类型 Mac Linux
用户主目录 /Users/username /home/username
临时目录 /private/tmp /tmp
系统日志 /var/log/system.log /var/log/syslog

实用场景示例

1. 批量重命名文件

# Mac(需安装 rename)
brew install rename
rename 's/old/new/' *.txt

# Linux(使用 rename 或 mmv)
sudo apt install rename
rename 'old' 'new' *.txt

2. 查找文件

# 按名称查找
find ~/ -name "*.log"

# 按内容查找
grep -rn "error" /var/log/

3. 压缩与解压

# 压缩目录为 tar.gz
tar -czvf archive.tar.gz /path/to/dir

# 解压 tar.gz
tar -xzvf archive.tar.gz

# 压缩为 zip(Mac/Linux 通用)
zip -r archive.zip /path/to/dir

安全与权限管理

1. 修改文件权限

chmod 755 script.sh     # 设置权限为 rwxr-xr-x
chown user:group file   # 修改文件所有者和组

2. SSH 密钥管理

# 生成密钥对
ssh-keygen -t ed25519

# 将公钥复制到服务器
ssh-copy-id user@remote-server

开发环境配置

1. Python 虚拟环境

# 创建虚拟环境
python -m venv myenv

# 激活环境(Mac/Linux)
source myenv/bin/activate

2. Node.js 版本管理(nvm)

# 安装 nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash

# 安装 Node.js
nvm install 18
nvm use 18

注意事项

  1. 权限警告

    • 慎用 sudorm -rf,避免误删系统文件。
    • Mac 启用 SIP(系统完整性保护),部分系统目录不可修改。
  2. 脚本兼容性

    • 在 Mac 上使用 GNU 工具(如 gsedgrep)可提高与 Linux 的兼容性:
      brew install coreutils findutils gnu-sed
      
  3. 日志与调试

    • 使用 journalctl(Linux)或 log show(Mac)查看系统日志。

通过掌握这些命令和示例,您可以高效操作 Mac 和 Linux 系统!遇到问题时,记得善用 man <命令> 查看手册(如 man ls)。

Flutter Linux应用初探

作者 Karl_wei
2025年3月30日 21:13

距离我上一篇文章,足足过去一年!!!
断更是艰难的过程,日常斥责自己没有作品。除了工作的忙碌、技术栈重心的变化外,AI的崛起带来技术交流平台的低迷,也是让我疲于更新的原因之一
近期重新投入Flutter技术,适配了Linux平台,才让我重新燃起奋笔疾书的欲望。Flutter for Linux在社区中的文章是非常之少的,期待这篇文章能给大家带来一些思考~

原理浅层分析

此次我是对旧项目进行Linux平台的适配,这个项目在Android和Windows平台已经顺利发布运行两年。因此这里省去创建运行项目的说明。
两年前创建的项目,期间跟随Flutter版本升级到3.22。在Linux平台的首次运行,竟然一次就顺利跑起来了。这让我十分的欣喜,而后不断思考:为何Flutter在Linux能如此的顺利运行?

1. 应用载体

Flutter Linux的载体是一个典型的GtkApplication。在main主入口,创建了MyApplication实例并运行应用程序。

#include "my_application.h"

int main(int argc, char** argv) {
  g_autoptr(MyApplication) app = my_application_new();
  return g_application_run(G_APPLICATION(app), argc, argv);
}

在my_application.h中,使用G_DECLARE_FINAL_TYPE宏定义了MyApplication的类型继承自GtkApplication

G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, GtkApplication)

创建了在my_application后,自然就会按顺序的执行GtkApplication的生命周期。
应用程序的主要生命周期包含以下几个关键阶段:

  • 启动(Startup)
  • 激活(Activate)这是最重要的阶段。
    主要完成:创建GTK窗口、设置窗口属性(大小、透明度等)、创建Flutter视图、注册Flutter插件...
  • 关闭(Shutdown)

image.png 总的来说,Flutter在Linux下的运行完全是依赖于GTK框架,通过以下步骤实现:

  • 创建GTK应用程序
  • 设置窗口和显示属性
  • 初始化Flutter引擎
  • 创建Flutter视图
  • 处理生命周期事件和消息

2. engine挂载

Flutter的engine和view是怎么跟GtkApplication关联上的呢?核心代码都在GApplication::activate的钩子中。

  • 创建一个FlDartProject
g_autoptr(FlDartProject) project = fl_dart_project_new();
  • 通过fl_dart_project_set_dart_entrypoint_arguments把启动参数,设置到Flutter层
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
  • 创建FlView,并且作为GTK_WIDGET添加到容器GTK_CONTAINER中
  FlView* view = fl_view_new(project);
  gtk_widget_show(GTK_WIDGET(view));
  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
  • 注册Flutter插件
  fl_register_plugins(FL_PLUGIN_REGISTRY(view));

整个过程与GTKWinodw是比较脱离的,跟Android FlutterActivity、Windows FlutterWindow的实现思路一模一样。
这也证明Flutter是个很纯粹的跨平台UI框架,脱离原生框架的束缚。所以3年前的项目,Linux端一次运行成功也就不足为奇了~

重点Tips

1. Flutter版本

Flutter的更新迭代是非常快的,并且桌面的支持也力不从心,所以对于一个新的平台来说,在开始适配的时候,一定要升级到最新版本,一定要用最新!!!

2. 设置窗口属性

Flutter是跨平台的UI,那么窗口的属性自然就无法快速去操作,比如:设置无标题栏、设置大小、居中等。
这里我们也不推荐在Flutter层面使用window_manager去操作,从性能和显示的实时效果出发,就应该在c++层处理完成
以下代码,为Flutter应用设置了依据分辨率适配大小、居中、隐藏标题栏、设置透明底等。

// 获取屏幕分辨率
gboolean GetScreenRect(gint *width, gint *height) {
  GdkDisplay *display = gdk_display_get_default();
  if (display) {
    GdkMonitor *monitor = gdk_display_get_primary_monitor(display);
    if (monitor) {
      GdkRectangle geometry;
      gdk_monitor_get_geometry(monitor, &geometry);
      *width = geometry.width;
      *height = geometry.height;
      return TRUE;
    }
  }
  return FALSE;
}

// 获取DPI
gint GetDpi() {
  GdkScreen *screen = gdk_screen_get_default();
  if (screen) {
    return gdk_screen_get_resolution(screen);
  }
  return 96; // 默认DPI
}

static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
                  gpointer user_data)
{
  cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
  cairo_paint(cr);
  return FALSE;
}

static void transparent_setup(GtkWidget *win)
{
  GdkScreen *screen;
  GdkVisual *visual;

  gtk_widget_set_app_paintable(win, TRUE);
  screen = gdk_screen_get_default();
  visual = gdk_screen_get_rgba_visual(screen);

  if (visual != NULL && gdk_screen_is_composited(screen)) {
    gtk_widget_set_visual(win, visual);
    g_signal_connect(G_OBJECT(win), "draw", G_CALLBACK(on_draw_event), NULL);
  }
}

// Implements GApplication::activate.
static void my_application_activate(GApplication* application) {
  MyApplication* self = MY_APPLICATION(application);
  GtkWindow* window =
      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));

  // Use a header bar when running in GNOME as this is the common style used
  // by applications and is the setup most users will be using (e.g. Ubuntu
  // desktop).
  // If running on X and not using GNOME then just use a traditional title bar
  // in case the window manager does more exotic layout, e.g. tiling.
  // If running on Wayland assume the header bar will work (may need changing
  // if future cases occur).
  gboolean use_header_bar = TRUE;
#ifdef GDK_WINDOWING_X11
  GdkScreen* screen = gtk_window_get_screen(window);
  if (GDK_IS_X11_SCREEN(screen)) {
    const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
    if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
      use_header_bar = FALSE;
    }
  }
#endif
  if (use_header_bar) {
    GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
    gtk_widget_show(GTK_WIDGET(header_bar));
    gtk_header_bar_set_title(header_bar, "SystemUpgradeMain");
    gtk_header_bar_set_show_close_button(header_bar, TRUE);
    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
  } else {
    gtk_window_set_title(window, "SystemUpgradeMain");
  }

  // 设置窗口透明
  transparent_setup(GTK_WIDGET(window));
  // 隐藏标题栏
  gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
  // 设置窗口居中
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

  // 获取缩放因子
  double scale_factor;
  gint screenWidth, screenHeight;
  auto default_resolution = 1.0 * 1920 / 1080;
  if (GetScreenRect(&screenWidth, &screenHeight)) {
    auto current_resolution = 1.0 * screenWidth / screenHeight;
    if (current_resolution > default_resolution) {
      scale_factor = 1.0 * screenHeight / 1080;
    } else {
      scale_factor = 1.0 * screenWidth / 1920;
    }
  } else {
    gint dpi = GetDpi();
    scale_factor = dpi / 96.0;
  }
  std::cout << "scale_factor: " << scale_factor << std::endl;
  // 设置窗口大小
  gtk_window_set_default_size(window, 1172*scale_factor, 731*scale_factor);

  gtk_widget_show(GTK_WIDGET(window));
  gtk_widget_set_visible(GTK_WIDGET(window), FALSE);

  g_autoptr(FlDartProject) project = fl_dart_project_new();
  fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);

  FlView* view = fl_view_new(project);
  gtk_widget_show(GTK_WIDGET(view));
  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));

  GdkRGBA background_color;
  gdk_rgba_parse(&background_color, "#ffffff");
  fl_view_set_background_color(view, &background_color);

  fl_register_plugins(FL_PLUGIN_REGISTRY(view));

  gtk_widget_grab_focus(GTK_WIDGET(view));
}

3. 查看Flutter for Linux源码

Flutter Linux的相关文章,全网都非常少见,其原因跟Flutter在Linux的投入,Linux系统下Flutter的应用生态都有所关系。好在官方的源代码文档,还是比较完整的:Flutter Linux源码
在给Linux窗口设置透明背景时,我们就遇到了不少坑。

  • 在Flutter 3.27之前,Flutter官方是没有提供透明窗口的方法的,FlutterView默认是黑色的。因此即便我们通过cairo_paint把GTKWindow绘制成透明的,上层的FlutterView依然不透明。
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
                  gpointer user_data)
{
  cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
  cairo_paint(cr);
  return FALSE;
}

static void transparent_setup(GtkWidget *win)
{
  GdkScreen *screen;
  GdkVisual *visual;

  gtk_widget_set_app_paintable(win, TRUE);
  screen = gdk_screen_get_default();
  visual = gdk_screen_get_rgba_visual(screen);

  if (visual != NULL && gdk_screen_is_composited(screen)) {
    gtk_widget_set_visual(win, visual);
    g_signal_connect(G_OBJECT(win), "draw", G_CALLBACK(on_draw_event), NULL);
  }
}
  • 于是我们通过搜索源码文档,很快定位到了相关的api,再到github上溯源其提交版本,很快的解决了这个问题。

image.png

写在后面

Linux App在国内的应用场景是比较少的,但随着接下来设备国产化的战略继续推进,我相信Flutter Linux会有进一步的需求。但是从生态上来看,不会C++的团队,在Flutter For Linux的道路上,是会遇到比较多的困难的。
Anyway,在国内鸿蒙化、国产化;世界范围AI编程、AOSP停止维护的大背景下,衷心希望Flutter桌面端越来越好吧~

❌
❌