Khắc phục lỗi 'Text file busy' khi cập nhật các tệp Binary trên Linux

beginner🐧 Linux2026-07-09| Linux (Ubuntu, Debian, CentOS, RHEL, Arch) sử dụng các hệ thống tệp tiêu chuẩn như Ext4 hoặc XFS.

Error Message

cp: cannot create regular file '/usr/local/bin/app': Text file busy
#linux#sysadmin#devops#troubleshooting#bash

Tình huống vấn đềHãy tưởng tượng bạn đang triển khai một bản build mới của dịch vụ Go hoặc công cụ C++ lên máy chủ production. Bạn chạy lệnh copy tiêu chuẩn để ghi đè lên tệp binary cũ:

cp /tmp/new_version /usr/local/bin/app

Thay vì cập nhật thành công, terminal của bạn lại hiển thị một lỗi khó chịu:

cp: cannot create regular file '/usr/local/bin/app': Text file busy

Linux kích hoạt chế độ bảo vệ này vì kernel từ chối cho phép bạn sửa đổi nội dung của một tệp binary trong khi một tiến trình đang thực thi nó. Nếu kernel cho phép ghi đè khi đang thực thi, ứng dụng đang chạy có khả năng sẽ bị crash hoặc gặp lỗi hỏng bộ nhớ (memory corruption) do mã nguồn bên dưới bị thay đổi đột ngột.

Bước 1: Xác định tiến trình đang khóa tệpĐể xử lý việc khóa tệp, trước tiên bạn cần tìm ra tiến trình đang giữ tệp đó. Hai công cụ chính sau đây sẽ giúp việc này trở nên dễ dàng.

Sử dụng fuserTiện ích fuser xác định tiến trình nào đang sử dụng một tệp hoặc thư mục cụ thể. Đây thường là cách nhanh nhất để lấy PID.

fuser /usr/local/bin/app

Bạn có thể thấy kết quả như sau:

/usr/local/bin/app:  4812e

Trong ví dụ này, 4812 là ID tiến trình (Process ID). Hậu tố e cho biết tệp đang được sử dụng dưới dạng tệp thực thi (executable).

Sử dụng lsofNếu bạn cần thêm thông tin ngữ cảnh, chẳng hạn như người dùng hoặc tên lệnh cụ thể, hãy sử dụng lsof (List Open Files):

lsof /usr/local/bin/app

Lệnh này cung cấp một bảng chi tiết hiển thị tên tiến trình, người dùng và loại bộ mô tả tệp (file descriptor).

Bước 2: Cách tiếp cận thủ công (Dừng và Thay thế)Cách tiếp cận đơn giản nhất thường là phương án "mạnh tay": dừng, thay thế và khởi động lại. Đây là cách an toàn nhất cho các ứng dụng không hỗ trợ nạp lại nóng (hot-reloading) tốt.

  • Chấm dứt tiến trình: kill 4812- Xác nhận tiến trình đã dừng, sau đó sao chép phiên bản mới: ``` cp /tmp/new_version /usr/local/bin/app
### Chiến lược sử dụng 'rm'Thay vì sử dụng `cp` (lệnh cố gắng mở tệp hiện có và cắt bớt nội dung), hãy sử dụng `rm` trước:

rm /usr/local/bin/app cp /tmp/new_version /usr/local/bin/app


Khi bạn `rm` một tệp binary đang chạy, mục nhập của tệp sẽ bị xóa khỏi thư mục. Tuy nhiên, dữ liệu thực tế vẫn còn trên đĩa miễn là tiến trình vẫn đang chạy. Lệnh `cp` mới sẽ tạo ra một inode hoàn toàn mới. Các tiến trình hiện tại vẫn tiếp tục chạy mã cũ trong bộ nhớ, trong khi bất kỳ lần khởi chạy mới nào cũng sẽ sử dụng phiên bản mới.
### Lệnh 'install'Lệnh `install` là cách chuyên nghiệp để xử lý việc này trong một lần thực hiện. Nó tự động unlink đích đến trước khi sao chép.

install -m 755 /tmp/new_version /usr/local/bin/app


Đây là quy trình tiêu chuẩn trong nhiều Makefile và pipeline CI/CD vì nó tránh hoàn toàn lỗi 'busy'.
## Bước 4: Quản lý qua SystemdĐối với các dịch vụ production được quản lý bởi `systemd`, bạn nên lồng việc cập nhật vào logic khởi động lại. Điều này đảm bảo log và các tiến trình con được xử lý sạch sẽ.

sudo systemctl stop my-app sudo install -m 755 /tmp/new_version /usr/local/bin/app sudo systemctl start my-app


## Xác minhXác nhận việc cập nhật thành công bằng cách kiểm tra siêu dữ liệu của tệp và trạng thái tiến trình:
- Kiểm tra dấu thời gian: ```
ls -l /usr/local/bin/app
```- Kiểm tra chuỗi phiên bản: ```
/usr/local/bin/app --version
```- Xem sơ đồ tiến trình: ```
ls -l /proc/$(pgrep app_name)/exe
``` Nếu liên kết tượng trưng (symlink) trỏ đến đường dẫn nhưng có kèm `(deleted)`, tiến trình vẫn đang chạy phiên bản cũ của tệp mà bạn đã unlink. Cần phải khởi động lại để chuyển sang mã mới.

Related Error Notes