linux-cli-tools简易模拟开发
环境配置
系统环境:ubuntu20.04,gcc,g++,cmake //可以参考之前的环境搭建详解
工具:vscode(ssh),VMware,mobaxterm
简易描述
linux-cli-tools是一个简易的Linux命令行工具,其中对于基础命令进行简易的模拟及其实现,如 ls,grep,cat 等等。
目的是为了更好的了解Linux基础命令的原理及提高在Linux中进行开发C++项目。
目录框架
~/code/linux-cli-tools/
- Makefile
~/code/linux-cli-tools/src/
- my_ls.cpp -> ls
- my_cat.cpp -> cat
- my_cp.cpp -> cp
- my_find.cpp -> find
- my_grep.cpp -> grep
- my_kill.cpp -> kill
- my_ps.cpp -> ps
- my_wc.cpp ->wc
实操流程:
为保证提高对Linux系统的熟练运用,该项目将在虚拟机开机后全程用vscode或mobaxterm中小黑盒进行命令操作。
建立目录
在前文所创建的目录(~/code)下创建该项目的整体目录文件框架
如图:
代码如下:
mkdir linux-cli-tools
cd linux-cli-tools
mkdir src
touch Makefile
cd src
touch my_ls.cpp my_cat.cpp my_cp.cpp my_find.cpp my_grep.cpp my_kill.cpp my_ps.cpp my_wc.cpp
编写程序
my_cat.cpp
#include<iostream>
#include<fstream>
#include<string>
void print_file(const std::string& filename)
{
std:: ifstream file(filename);
//创建一个文件流对象file(filename为该文件的路径及其名称)
//判断能否打开
if(!file.is_open())
{
std::cerr<<"Error: Unanle to open file"<<filename<<std::endl;
return;
}
//如果成功打开那就getline 一行行输出
std::string line;
while(std::getline(file,line))
{
std::cout<<line<<std::endl;
}
}
int main(int argc,char* argv[])
{
if(argc<2)
{
std::cerr<<"Usage: "<<argv[0]<<"<filename>"<<std::endl;
return 1;
}
print_file(argv[1]);
return 0;
}
my_cp.cpp
#include <iostream>
#include <fstream>
void copy_file(const std::string& src, const std::string& dest)
{
std::ifstream src_file(src, std::ios::binary);
if (!src_file)
{
std::cerr << "Error: Unable to open source file " << src << std::endl;
return;
}
std::ofstream dest_file(dest, std::ios::binary);
if (!dest_file)
{
std::cerr << "Error: Unable to open destination file " << dest << std::endl;
return;
}
dest_file << src_file.rdbuf();
}
int main(int argc, char* argv[])
{
if (argc < 3) {
std::cerr << "Usage: " << argv[0] << " <source> <destination>" << std::endl;
return 1;
}
copy_file(argv[1], argv[2]);
return 0;
}
my_find.cpp
#include <iostream>
#include <dirent.h>
#include <sys/stat.h>
#include <cstring>
#include <string>
void find_file(const std::string& dir, const std::string& target)
{
DIR* dp = opendir(dir.c_str());
if (!dp) {
std::cerr << "Error: Unable to open directory " << dir << std::endl;
return;
}
struct dirent* entry;
char path[1024];
while ((entry = readdir(dp)) != nullptr)
{
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
snprintf(path, sizeof(path), "%s/%s", dir.c_str(), entry->d_name);
struct stat st;
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
{
find_file(path, target);
} else if (strstr(entry->d_name, target.c_str()))
{
std::cout << path << std::endl;
}
}
closedir(dp);
}
int main(int argc, char* argv[])
{
//argc的作用是判断传入的参数是否足够
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << " <directory> <filename>" << std::endl;
return 1;
}
find_file(argv[1], argv[2]);
return 0;
}
my_grep.cpp
#include<iostream>
#include<fstream>
#include<regex>
#include<string>
void grep_file(const std::string& pattern,const std::string& filename)
{
std::ifstream file(filename);
if(!file.is_open())
{
std::cerr<<"Error:Unable to open file "<<filename<<std::endl;
return;
}
std::regex regex(pattern);
std::string line;
while(std::getline(file,line))
{
if(std::regex_search(line,regex))
{
std::cout<<line<<std::endl;
}
}
}
int main(int argc,char* argv[])
{
if(argc<3)
{
std::cerr<<"Usage: "<<argv[0]<<"<pattern> <filename> "<<std::endl;
return 1;
}
grep_file(argv[1],argv[2]);
return 0;
}
my_kill.cpp
#include <iostream>
#include <csignal>
void kill_process(int pid, int signal)
{
if (kill(pid, signal) == -1)
{
std::cerr << "Error: Unable to send signal to process " << pid << std::endl;
}
else
{
std::cout << "Signal " << signal << " sent to process " << pid << std::endl;
}
}
int main(int argc, char* argv[])
{
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << " <pid> <signal>" << std::endl;
return 1;
}
int pid = std::stoi(argv[1]);
int signal = std::stoi(argv[2]);
kill_process(pid, signal);
return 0;
}
my_ls.cpp
#include<iostream>
#include<dirent.h>
#include<sys/stat.h>
#include<cstring>
void list_directory(const std::string& path)
{
DIR* dir = opendir(path.c_str());
if(!dir)
{
std::cerr << "Error: Unable to open directory "<<path<<std::endl;
return;
}
struct dirent* enrty;
while((enrty = readdir(dir))!=nullptr)
{
std::cout<<enrty->d_name<<std::endl;
}
closedir(dir);
}
int main(int argc,char* argv[])
{
if(argc<2)
{
list_directory(".");
}
else
{
list_directory(argv[1]);
}
return 0;
}
my_ps.cpp
#include <iostream>
#include <dirent.h>
#include <sys/types.h>
#include <fstream>
#include <string>
#include <unistd.h>
// 获取进程的命令名称(即进程的执行文件)
std::string get_process_name(int pid)
{
std::string path = "/proc/" + std::to_string(pid) + "/comm";
std::ifstream file(path);
std::string process_name;
if (file.is_open())
{
std::getline(file, process_name); // 读取进程名
file.close();
}
return process_name;
}
void my_ps()
{
DIR *dir = opendir("/proc");
if (dir == nullptr)
{
std::cerr << "Failed to open /proc directory." << std::endl;
return;
}
struct dirent *entry;
while ((entry = readdir(dir)) != nullptr)
{
// 检查目录名是否为数字(即进程的 PID)
if (entry->d_type == DT_DIR && std::isdigit(entry->d_name[0]))
{
int pid = std::stoi(entry->d_name); // 将 PID 转换为整数
std::string process_name = get_process_name(pid); // 获取进程名称
std::cout << "PID: " << pid << " - " << process_name << std::endl;
}
}
closedir(dir);
}
int main()
{
my_ps(); // 执行 my_ps 查看进程
return 0;
}
my_wc.cpp
#include <iostream>
#include <fstream>
#include <string>
void count_file(const std::string& filename)
{
std::ifstream file(filename);
if (!file.is_open())
{
std::cerr << "Error: Unable to open file " << filename << std::endl;
return;
}
int lines = 0, words = 0, chars = 0;
std::string word;
while (file >> word)
{
++words;
}
file.clear(); // Clear EOF flag
file.seekg(0); // Go back to the start of the file
std::string line;
while (std::getline(file, line))
{
++lines;
chars += line.size();
}
std::cout << "Lines: " << lines << ", Words: " << words << ", Characters: " << chars << std::endl;
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " <filename>" << std::endl;
return 1;
}
count_file(argv[1]);
return 0;
}
Makefile
CXX = g++
CXXFLAGS = -std=c++11 -Wall
SRCDIR = src
SRC = $(wildcard $(SRCDIR)/*.cpp)
OBJ = $(SRC:.cpp=.o)
TARGETS = $(SRC:$(SRCDIR)/%.cpp=%)
all: $(TARGETS)
%: $(SRCDIR)/%.cpp
$(CXX) $(CXXFLAGS) $< -o $@
clean:
rm -rf $(OBJ) $(TARGETS)
.PHONY:clean
编译
打开终端(vscode或者mobaxtrem都行),到Makefile文本所在的目录
make
然后会生成相应的各个可执行文件。
测试
测试环节可以对应Linux中命令进行同等参数操作
例如
./my_cat ../Makefile
清除可执行文件
make clean
附加
简易制作可持续的进程
linux-cli-tools目录下创建demo.cpp
代码如下:
#include <iostream>
#include <unistd.h> // 用于 fork()
#include <signal.h> // 用于信号处理
// 子进程的工作函数
void child_process()
{
int cnt = 1;
while (true)
{
std::cout << "Child process is running..."<<cnt++<<" "<< std::endl;
sleep(1); // 每秒输出一次
}
}
int main() {
pid_t pid = fork(); // 创建子进程
if (pid < 0)
{
std::cerr << "Fork failed!" << std::endl;
return 1;
}
if (pid == 0)
{
// 子进程代码
child_process();
}
else
{
// 父进程代码
std::cout << "Parent process created a child process with PID: " << pid << std::endl;
// 父进程继续运行,可以做其他事情,或者等待子进程
while (true)
{
sleep(5); // 父进程等待5秒
}
}
return 0;
}
编译
终端执行
g++ demo.cpp -o demo
运行可执行文件demo
./demo
当前终端显示且继续增加
开启另一个终端进行
./my_kill 10701 9
则上一个终端停止运行但未退出