关于命令行交互自动化,及pyinstaller打包wexpect的问题

Python自动化工具

用来执行命令并进行交互,比如需要输入账号密码或者确认的场景

linux平台可以用pexpect,但是windows平台有一些差异,比较好用的是pexpect的变种wexpect,如果脚本中用了wexpect,并且要打包成onefile,可以

参考github首先打包wexpect

1.进入wexpect目录执行

pyinstaller main.py -n wexpect

会生成dist文件夹

2.python代码A.py中使用wexpect,注意wexpect.spawn前后必须按照下面添加代码

python 复制代码
import sys,os,wexpect
#spawn前
real_executable = sys.executable
try:
    if sys._MEIPASS is not None:
        sys.executable = os.path.join(sys._MEIPASS, "wexpect", "wexpect.exe")
except AttributeError:
    pass
child = wexpect.spawn('ssh root@192.168.47.128')
sys.executable = real_executable
#spawn后
try:
    child.expect('password',timeout=1)
    child.sendline("root@123")
    child.expect('#',timeout=1)
    child.sendline("touch wexpect")
    child.sendline("exit")
except Exception as e:
    print("timeout")
print('1.before = ',child.before)
print('2.after = ',child.after)
child.wait()

3.打包成onefile

pyinstaller --onefile --add-data "wexpect路径\dist;." A.py

Windows伪控制台

很少用到,只能参考windows官方文档自己写,启动伪控制台,并且通过管道直接和伪控制台交互,非常方便,传送门

自己随便写的demo如下:

cpp 复制代码
// PseudoConsoleDemo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <thread>
#include <string>
#include <codecvt>
#include <memory>
using namespace std;

void Log(string info) 
{
	//string cmd = "echo " + info;
	printf(info.c_str());
}

std::string UTF8ToLocale(const std::string& utf8Str)
{
	//Convert utf8 to Unicode
	std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
	std::wstring tmpWstr = conv.from_bytes(utf8Str);
	//Conver widestr to system code page
	int len = WideCharToMultiByte(CP_ACP, NULL, tmpWstr.c_str(), -1, NULL, NULL, NULL, NULL);
	char *str = new char[len];
	WideCharToMultiByte(CP_ACP, NULL, tmpWstr.c_str(), -1, str, len, NULL, NULL);
	return str;
}

HRESULT PrepareStartupInformation(HPCON hpc, STARTUPINFOEXW* psi)
{
	// Prepare Startup Information structure
	STARTUPINFOEXW si;
	ZeroMemory(&si, sizeof(si));
	si.StartupInfo.cb = sizeof(STARTUPINFOEX);

	// Discover the size required for the list
	SIZE_T bytesRequired;
	InitializeProcThreadAttributeList(NULL, 1, 0, &bytesRequired);

	// Allocate memory to represent the list
	si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, bytesRequired);
	if (!si.lpAttributeList)
	{
		return E_OUTOFMEMORY;
	}

	// Initialize the list memory location
	if (!InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &bytesRequired))
	{
		HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
		return HRESULT_FROM_WIN32(GetLastError());
	}

	// Set the pseudoconsole information into the list
	if (!UpdateProcThreadAttribute(si.lpAttributeList,
		0,
		PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
		hpc,
		sizeof(hpc),
		NULL,
		NULL))
	{
		HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
		return HRESULT_FROM_WIN32(GetLastError());
	}

	*psi = si;

	return S_OK;
}
bool WritePipe(HANDLE pipeHd, const char DataBuffer[])
{
	DWORD dwBytesToWrite = (DWORD)strlen(DataBuffer);
	DWORD dwBytesWritten = 0;
	BOOL bErrorFlag = FALSE;



	bErrorFlag = WriteFile(
		pipeHd,           // open file handle
		DataBuffer,      // start of data to write
		dwBytesToWrite,  // number of bytes to write
		&dwBytesWritten, // number of bytes that were written
		NULL);
	return bErrorFlag;
}

bool ReadPipe(HANDLE pipeHd)
{
	const int BUFFERSIZE = 4096;
	char   ReadBuffer[BUFFERSIZE] = { 0 };

	if (pipeHd == INVALID_HANDLE_VALUE)
	{
		//printf(("Terminal failure: unable to open file \"\" for read.\n"));
		return false;
	}

	// Read one character less than the buffer size to save room for
	// the terminating NULL character. 
	DWORD dwBytesRead;
	DWORD dwBytesToRead = BUFFERSIZE - 1;
	
	if (FALSE == ReadFile(pipeHd, ReadBuffer, dwBytesToRead, &dwBytesRead, NULL))
	{

		//printf("Terminal failure: Unable to read from file.\n GetLastError=%08x\n", GetLastError());
		return false;
	}


	// This is the section of code that assumes the file is ANSI text. 
	// Modify this block for other data types if needed.

	if (dwBytesRead > 0 && dwBytesRead <= dwBytesToRead)
	{
		ReadBuffer[dwBytesRead] = '\0'; // NULL character

		//printf(("Data read from  (%d bytes): \n"), dwBytesRead);
		//PseudoConsole use utf8 encode
		Log(UTF8ToLocale(ReadBuffer));
		return true;
	}
	else if (dwBytesRead == 0)
	{
		//printf(("No data read from file\n"));
	}
	else
	{
		//printf("\n ** Unexpected value for dwBytesRead ** \n");
	}
	return false;
}
PWSTR String2PWSTR(const string& str)
{
	PWSTR pwstr;
	int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.size(), NULL, 0);
	pwstr = new WCHAR[len + 1];
	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.size(), pwstr, len);
	pwstr[len] = '\0';
	return pwstr;
}
HPCON SetUpPseudoConsole(std::string cmd, HANDLE& read, HANDLE& write, PROCESS_INFORMATION& proc)
{
	COORD size = { 1000, 500 };
	HRESULT hr = S_OK;

	// Create communication channels

	// - Close these after CreateProcess of child application with pseudoconsole object.
	HANDLE inputReadSide, outputWriteSide;

	// - Hold onto these and use them for communication with the child through the pseudoconsole.
	HANDLE outputReadSide, inputWriteSide;

	if (!CreatePipe(&inputReadSide, &inputWriteSide, NULL, 0))
	{
		return NULL;
	}

	if (!CreatePipe(&outputReadSide, &outputWriteSide, NULL, 0))
	{
		return NULL;
	}

	HPCON hPC;

	hr = CreatePseudoConsole(size, inputReadSide, outputWriteSide, 0, &hPC);
	if (FAILED(hr))
	{
		return NULL;
	}
	STARTUPINFOEXW siEx;
	PrepareStartupInformation(hPC, &siEx);
	// Create mutable text string for CreateProcessW command line string.


	const string cmdStr = "C:\\windows\\system32\\cmd.exe /k \"echo off\"";
	PCWSTR childApplication = String2PWSTR(cmdStr);
	//PCWSTR childApplication = L"C:\\windows\\system32\\cmd.exe /k \"net use \\\\192.168.47.128\"";

	// Create mutable text string for CreateProcessW command line string.
	const size_t charsRequired = wcslen(childApplication) + 1; // +1 null terminator
	PWSTR cmdLineMutable = (PWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(wchar_t) * charsRequired);

	if (!cmdLineMutable)
	{
		return NULL;
	}

	wcscpy_s(cmdLineMutable, charsRequired, childApplication);

	PROCESS_INFORMATION pi;
	ZeroMemory(&pi, sizeof(pi));

	// Call CreateProcess
	if (!CreateProcessW(NULL,
		cmdLineMutable,
		NULL,
		NULL,
		FALSE,
		EXTENDED_STARTUPINFO_PRESENT,
		NULL,
		NULL,
		&siEx.StartupInfo,
		&pi))
	{
		HeapFree(GetProcessHeap(), 0, cmdLineMutable);
		return NULL;
	}
	CloseHandle(inputReadSide);
	CloseHandle(outputWriteSide);
	//if (!WritePipe(inputWriteSide, "net use \\\\192.168.47.128\r")) {
	//	printf("write error");
	//}
	read = outputReadSide;
	write = inputWriteSide;
	proc = pi;
	return hPC;
}
int main()
{

	auto t = std::thread([]() {
		HANDLE read, write;
		PROCESS_INFORMATION pi;
		HPCON hpc = SetUpPseudoConsole("net use \\\\192.168.47.128", read, write, pi);
		DWORD exitCode;
		if (GetExitCodeProcess(pi.hProcess, &exitCode)) {
			//printf("get exit code success ,code=%d", exitCode);
			STILL_ACTIVE;
			if (exitCode == STILL_ACTIVE) {
				//printf("process alive");
			}
		}
		else {
			Log("get exit code failed");
		}

		if (!ReadPipe(read)) {
			Log("read error");
		}

		if (!WritePipe(write, "net use \\\\192.168.47.128\r")) {
			Log("write error");
		}
		if (!ReadPipe(read)) {
			Log("read error");
		}

		if (!WritePipe(write, "smbshare\r")) {
			Log("write error");
		}

		if (!ReadPipe(read)) {
			Log("read error");
		}
		if (!WritePipe(write, "smbshare\r")) {
			Log("write error");
		}

		if (!ReadPipe(read)) {
			Log("read error");
		}

		Sleep(100);
		if (GetExitCodeProcess(pi.hProcess, &exitCode)) {
			Log("get exit code success ,code=" + exitCode);
			STILL_ACTIVE;
			if (exitCode == STILL_ACTIVE) {
				Log("process alive");
			}
		}
		WaitForSingleObject(pi.hProcess, 0);
		WaitForSingleObject(pi.hThread, 0);
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
		ClosePseudoConsole(hpc);
		//TerminateProcess

	});
	t.join();
}
相关推荐
数据狐(Datafox)3 小时前
京东商品列表API技术解析与落地应用(含标准 JSON 示例)
java·大数据·前端·人工智能·python·数据分析·json
量化吞吐机3 小时前
2026年下半年手工交易规则走向量化表达,产品该先接住哪一步
人工智能·python
Metaphor6924 小时前
使用 Python 读取和删除 Excel 文件属性
python·excel
迷迭香yy5 小时前
Python构建转融券多空识别系统从接口到因子的全流程 IG50免费开源股票数据API接口
开发语言·python·开源
月光船幽幽5 小时前
真实即粗糙,光滑是伪造
人工智能·python
一次旅行5 小时前
Attention机制从数学到工程:拆解缩放点积+多头注意力|附可运行PyTorch实现与踩坑指南
人工智能·pytorch·python
泡干脆面就番茄5 小时前
NumPy 科学计算完全指南:从数组创建到广播机制
python·numpy
denggun123455 小时前
信号量(DispatchSemaphore vs AsyncSemaphore)、swift协作式线程池 and python信号量
开发语言·python·swift
起光6 小时前
Python类与对象(一)
python
阿童木写作6 小时前
跨马翻译:AI批量图片翻译工具,视频字幕翻译与智能抠图一站式解决
大数据·人工智能·python·音视频