【回顾】Linux下的串口编程(实现AT指令的收发)

前言

现树莓派下基于4G模块(EC200U-CN)的短信收发功能,其实就是通过串口发送AT指令来实现的,所以在这个项目中我们第一步首先要学习Liunx下的串口编程;学习linux下的串口编程,则需要了解串口通信协议。串口通信,主要设置好波特率、数据位、奇偶校验位、停止位等参数。

1. 相关知识

1.1 termios 结构

termios 结构是在POSIX规范中定义的标准接口,它类似于系统V中的termio接口,通过设置termios类型的数据结构中的值和使用一小组函数调用,你就可以对终端接口进行控制。

struct termios
{
       tcflag_t c_iflag;           //输入模式标志
       tcflag_t c_oflag;           //输出模式标志
       tcflag_t c_cflag;           //控制模式标志
       tcflag_t c_lflag;           //本地模式标志
       cc_t    c_cc[NCCS];        //控制字符

       speed_t c_isspeed;         //输入波特率
       speed_t c_ospedd;          //输出波特率
}

通过设定对应功能的结构体成员以达到控制串口属性的目的,属性的设置是通过标志位来实现的,通过与,或和取反等方式,来将对应的功能模块的标志位置0或者置1(与非运算置0,或运算置1),从而告诉系统是否要有此功能,关于次结构体详细查看:termio结构体

1.2 相关API函数

1.2.1 open函数

fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NONBLOCK);

Open函数中除普通参数外,另有两个参数O_NOCTTY和O_NDELAY。
O_NOCTTY: 通知linux系统,这个程序不会成为这个端口的控制终端,如果不使用该选项,一些输入字符
可能会影响进程的运行(如一些产生中断信号的键盘输入字符等)。
O_NDELAY: 通知linux系统不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。

1.2.2 fcntl函数

fcntl() 函数可以对一个已经打开的文件描述符执行一系列控制操作,譬如复制一个文件描述符(与 dup 、 dup2 作用相同)、获取 / 设置文件描述符标志、获取 / 设置文件状态标志等,类似于一个多功能文件描述符管理工具箱。

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ )

fd : 文件描述符。
cmd : 操作命令。此参数表示我们将要对 fd 进行什么操作,cmd 操作命令大致可以分为以下 5 种功能:
复制文件描述符( cmd=F_DUPFD 或 cmd=F_DUPFD_CLOEXEC );
获取 / 设置文件描述符标志( cmd=F_GETFD 或 cmd=F_SETFD );
获取 / 设置文件状态标志( cmd=F_GETFL 或 cmd=F_SETFL );
获取 / 设置异步 IO 所有权( cmd=F_GETOWN 或 cmd=F_SETOWN );
获取 / 设置记录锁( cmd=F_GETLK 或 cmd=F_SETLK);
fcntl 函数是一个可变参函数,第三个参数需要根据不同的 cmd 来传入对应的实参,配合 cmd 来使用。
返回值: 执行失败情况下,返回 -1 ,并且会设置 errno ;
执行成功的情况下,其返回值与 cmd (操作命 令)有关,
譬如 cmd=F_DUPFD (复制文件描述符)将返回一个新的文件描述符、 cmd=F_GETFD (获取文 件描述符标志)将返回文件描述符标志、cmd=F_GETFL (获取文件状态标志)将返回文件状态标志等。

1.2.3 isatty函数

#include<unistd.h>

int isatty(int desc);

如果参数desc所代表的文件描述词为一终端机则返回1,否则返回0。

返回值
如果文件为终端机则返回1,否则返回0。

1.2.4 tcgetattr() 与 tcsetattr()

tcgetattr()
int tcgetattr(int fd,struct termios &termios_p);

参数
int fd: 打开串口文件后,获取到的文件描述符
struct termios &termios_p: termios 类型的结构体,包含在 <termios.h> 头文件中,这里需要传地址或指针
返回值:成功返回 0,失败返回 -1
函数功能:
功能:获取文件描述符对应串口的原始属性,并保存在第二个参数中,通常获取的原始属性需要进行备份,在程序退出之前要将其修改回来,否则无法继续使用串口。

tcsetattr()
int tcsetattr(int fd,int actions,const struct termios *termios_p);

参数
int fd: 要设置属性的文件描述符
int actions: 设置属性时,可以控制属性生效的时刻,actions可以取下面几个值:
TCSANOW: 立即生效
TCADRAIN: 改变在所有写入fd 的输出都被传输后生效。这个函数应当用于修改影响输出的参数时使用。(当前输出完成时将值改变)
TCSAFLUSH :改变在所有写入fd 引用的对象的输出都被传输后生效,所有已接受但未读入的输入都在改变发生前丢弃(同TCSADRAIN,但会舍弃当前所有值)。
*termios termios_p: 用来设置的串口属性的结构体指针,通过设置好属性的termios后,传入函数即可
返回值: 成功返回 0 ,失败返回-1.
功能:设置文件描述符对应串口的属性。

1.2.5 cfsetispeed() 与 cfsetospeed()

cfsetispeed() —— 串口输入波特率的设置
cfsetospeed() —— 串口输出波特率的设置

int cfsetispeed(struct termios *termptr, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
  • 参数

termios_p: 通过结构体来设置串口通信的属性,这是指向该结构体 termios 的指针;
speed: 因为串口通信没有时钟线,是一种异步通信,要想达到通信双发收发信息的统一,就需要设置输入输出波特率相同。

  • 返回值:

如果成功返回0,否则返回-1

  • 波特率常量:

CBAUD 掩码
  B0 0波特
  B50 50波特
  B75 75波特
  B110 100波特
  B134 134波特
  B150 150波特
  B200 200波特
  B300 300波特
  B600 600波特
  B1200 1200波特
  B1800 1800波特
  B2400 2400波特
  B9600 9600波特
  B19200 19200波特
  B38400 38400波特
  B57600 57600波特
  B115200 115200波特

1.2.6 tcflush()

#include <termios.h>

int tcflush(int fd,int quene)

参数
fd: 要操作的文件描述符
quene: 操作位置,可以取下面三个值:
TCIFLUSH:清空输入队列
TCOFLUSH:清空输出队列
TCIOFLUSH:清空输入输出队列
返回值:成功返回 0 ,失败返回 -1

注意:
在打开串口后,串口其实已经可以开始读取 数据了 ,这段时间用户如果没有读取,将保存在缓冲区里,如果用户不想要开始的一段数据,或者发现缓冲区数据有误,可以使用这个函数清空缓冲
需要注意,如果是在任务中,需要不停地写入数据到串口设备,千万不能在每次写入数据到设备前,进行flush以前数据的操作,因为两次写入的间隔是业务控制的,内核不会保证在两次写入之间一定把数据发送成功。flush操作一般在打开或者复位串口设备时进行操作。

2. minicom工具

minicom是LIUNX环境下的一个串口调试工具。比较主流,用户较广。也能找到它的源码,非常适合开发者使用与学习。下面就开始本文正篇。(为什么要说这个呢?因为我们接下来就是要用代码来实现这个minocom这个工具)

2.1 安装minicom工具

sudo apt-get install minicom

sudo minicom -h (查看命令的帮助信息)
在这里插入图片描述

2.2 端口配置

sudo minicom -s
在这里插入图片描述
然后选择第三个 Serial port setup(串口设置)
按下A键即可修改串口路径名(其他的值一般已经默认好,波特率这里设为115200),修改完后按下回车,再按一次回车返回上一级目录,保存设置。
在这里插入图片描述
在这里插入图片描述
选择 Exit 退出,就会调到如下界面:
在这里插入图片描述

2.3 设置回显

现在就可以输入AT指令但是不会有回显,接下来要设置回显
 字符回显有两种方式,一种是模块的字符回显,一种是minicom的字符回显。
  一、执行AT命令“ATE1”打开模块的字符回显功能。打开后输入一个字符就能看到模块回显一个字符了。
  二、 如果不想打开模块的字符回显,可以使用minicom提供的字符回显功能。在minicom中按下crtl键,再按下“A”键,再按下’Z‘键,看到如下:
在这里插入图片描述
在这里插入图片描述
再按下“E”键就可以打开了。再输入“AT”,就会回显两次了。
在这里插入图片描述

3. 代码具体实现

3.1 流程图

在这里插入图片描述

3.2 代码如下

3.2.1 serial.c

主函数的实现,主要功能:命令行参数解析(从命令行输入串口名,波特率,数据位,奇偶校验位,停止位),安转信号,使用多路复用select监听标准输入和串口。

#include "serial.h"

int     g_stop = 0;

int main(int argc, char **argv)
{
    int             opt = -1;
    int             rv = 0;
    char            *progname = NULL;
    fd_set          rdfds;
    char            send_buf[128] = {0};
    char            rece_buf[128] = {0};
    serial_ctx_t    serial;

    struct option longopts[] = {
        {"name",required_argument,NULL,'n'},
        {"baudrate",required_argument,NULL,'b'},
        {"databits",required_argument,NULL,'d'},
        {"even",no_argument,NULL,'e'},
        {"odd",no_argument,NULL,'o'},
        {"stopbits",required_argument,NULL,'s'},
        {"help",no_argument,NULL,'h'},
        {NULL,0,NULL,0}
    };

    progname = basename(argv[0]);

    memset(&serial,0,sizeof(serial_ctx_t));

    while((opt = getopt_long(argc,argv,":n:b:d:eos:h",longopts,NULL)) != -1)
    {
        switch(opt)
        {
            case 'n': strncpy(serial.serialname,optarg,sizeof(serial.serialname)); break;
            case 'b': serial.baudrate = atoi(optarg); break;
            case 'd': serial.databits = atoi(optarg); break;
            case 'e': serial.parity = 0; break;
            case 'o': serial.parity = 1; break;
            case 's': serial.stopbits = atoi(optarg); break;
            case 'h': printf_help(progname); return 0;
            default: return 0;
        }
    }

    if(0 == strlen(serial.serialname))
    {
        printf_help(progname);
        return 1;
    }

    if((rv = serial_open(&serial)) < 0)
    {
        printf("open serial port: %s failure and rv: %d\n",serial.serialname,rv);
        return 2;
    }

    /* serial port init and set serial port related  value */
    if((rv = serial_init(&serial)) < 0)
    {
        printf("serial port init failure rv: %d\n",rv);
        return 3;
    }

    /* ctrl+C capture SIGINT execute sig_hand1 function */
    signal(SIGINT,sig_handl);

    fflush(stdin);

    printf("-----------------------------------------------------------------------------\n");
    printf("|                   Start to comunicate with serial port                    |\n");
    printf("-----------------------------------------------------------------------------\n");

    while(!g_stop)
    {
        FD_ZERO(&rdfds);
        FD_SET(STDIN_FILENO,&rdfds); //Standard input joins the collection
        FD_SET(serial.fd,&rdfds);   //serial port fd joins the collection

        rv = select(serial.fd + 1,&rdfds,NULL,NULL,NULL);
        if(rv < 0)
        {
            printf("main_select() serial post failure: %s and program exit!\n",strerror(errno));
            break;
        }
        else if(0 == rv)
        {
            printf("select() serial post get timeout\n");
            continue;
        }

        if(FD_ISSET(STDIN_FILENO,&rdfds))
        {
            memset(send_buf,0,sizeof(send_buf));

            fgets(send_buf,sizeof(send_buf),stdin);

            packet_buf(send_buf);

            rv = serial_send(send_buf,serial,strlen(send_buf));
            if(rv < 0)
            {
                printf("serial port send data failure and rv: %d\n",rv);
                break;
            }
            fflush(stdin);
        }
        else if(FD_ISSET(serial.fd,&rdfds))
        {
            memset(rece_buf,0,sizeof(rece_buf));
            
            rv = serial_rece(rece_buf,serial,sizeof(rece_buf),TIMEOUT);
            if(rv < 0)
            {
                printf("serial port receive data failure and rv: %d\n",rv);
                break;
            }

            printf("%s\n",rece_buf);
            fflush(stdout);
        }
    }

    printf("exit\n");
    if((rv = serial_close(&serial)) < 0)    
    {
        printf("serial port close failure and rv: %d\n",rv);
        return 4;
    }

    return 0;
}

void packet_buf(char *buf)
{
    int i = strlen(buf);
    strcpy(&buf[i-1],"\r");

}

/* SIGINT handle function */
void sig_handl(int signum)
{
    g_stop = 1;
}

void printf_help(char *progname)
{
    printf("-------------------------  The correct input is as follows  --------------------------\n");
    printf("../bin/%s --name /dev/xxx --baudrate xxx --databits xxx (--even) (--odd) --stopbits xxx (--help)\n",progname);
    printf("../bin/%s --name /dev/ttyUSB0 --baudrate 115200 --databits 8 --even --stopbits 2\n",progname);
    printf("[--name]            is name of the serial port device you want to use. eg: --name /dev/ttyUSB0\n");
    printf("[--baudrate]        is setting baudrate. eg: --baudrate 115200\n");
    printf("[--databits]        is setting databits. eg: --databits 8\n");
    printf("[(--even) (--odd)]  is setting even parity or odd parity or no parity. eg: --even or --odd or not fill(no parity)\n");
    printf("[--stopbits]        is setting stopbits. eg: --stopbits 1\n");
    printf("[--help]            is help message\n");
}

3.2.2 serial.h

#ifndef  _SERIAL_H_
#define  _SERIAL_H_

#include <libgen.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/select.h>
#include <signal.h>
#include "serialinit.h"
#include "serialswap.h"

#define TIMEOUT     2

void packet_buf(char *buf);
void sig_handl(int signum);
void handle_stop(int sig);
void printf_help(char *progname);

#endif   /* ----- #ifndef _COMPORT_H_  ----- */

3.2.3 erialinit.c

串口初始化文件,主要功能:打开串口、串口的相关属性设置(包括波特率,数据位,奇偶校验位,停止位等)、恢复串口原来属性以及关闭串口。

#include "serialinit.h"

int serial_open(serial_ctx_t *serial)
{
    if(!serial)
    {
        printf("%s,Invalid input arguments\n",__func__);
        return -1;
    }

    /* open serial port */
    serial->fd = open(serial->serialname,O_RDWR | O_NOCTTY | O_NONBLOCK);
    if(serial->fd < 0)
    {
        printf("open serial port failure: %s\n",strerror(errno));
        return -2;
    }

    /* aet serial port is blocked */
    if(fcntl(serial->fd,F_SETFL,0) < 0)
    {
        printf("fcntl check failure\n");
        return -3;
    }

    /* check whether it is a terminal device */
    if(0 == isatty(serial->fd))
    {
        printf("[%s:%d] is not a terminal device\n",serial->serialname,serial->fd);
        return -3;
    }

    printf("open serial port: %s successfully\n",serial->serialname);

    return 0;
}

int serial_close(serial_ctx_t *serial)
{
    if(!serial)
    {
        printf("%s,Invalid input arguments\n",__func__);
        return -1;
    }

    if(tcsetattr(serial->fd,TCSANOW,&(serial->oldtermios)) < 0)
    {
        printf("set serial port old options failure: %s\n",strerror(errno));
        return -2;
    }

    close(serial->fd);

    return 0;
}

int serial_init(serial_ctx_t *serial)
{
    struct termios  newtermios;
    char            setbaudrate[32] = {0};

    if(!serial)
    {
        printf("%s,Invalid input arguments\n",__func__);
        return -1;
    }

    memset(&newtermios,0,sizeof(newtermios));
    memset(&(serial->oldtermios),0,sizeof(serial->oldtermios));

    /* Get the original properties and copy them */
    if(tcgetattr(serial->fd,&(serial->oldtermios)) < 0)
    {
        printf("get serial port oldtermios failure: %s\n",strerror(errno));
        return -2;
    }

    /* use serial port properties */
    if(tcgetattr(serial->fd,&newtermios) < 0 )
    {
        printf("get serial port newtermios failure: %s\n",strerror(errno));
        return -3;
    }

    /* Modify the control mode to ensure that the program does not occupy the serial port */
    newtermios.c_cflag |= CLOCAL;

    /* Start the receiver and read the input data from the serial port */
    newtermios.c_cflag |= CREAD;

    /* CSIZE character size mask that will be associated with setting databits to the Peugeot position zero */
    newtermios.c_cflag &= ~CSIZE;

    /*
     * ICANON: standard input
     * ECHO:   the entered characters are displayed
     * ECHOE:  If the ICANON flag is set, ERASE deletes the previous character and WERASE deletes the previous word 
     * ISIG:   When the INTR/QUIT/SUSP/DSUSP characters are received, a corresponding signal is generated 
    */
    newtermios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    /*
     * BRKINT: BREAK discards the data in the input and output queues (flush)
     * ICRNL:  Convert CR in the input to NL
     * INPCK:  Parity check is allowed
     * ISTRIP: Strip the eighth bit 
     * IXON:   Stripping the 8th bit allows XON/XOF flow control on the output
    */
    newtermios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);

    /* OPOST: Represents the output after processing, according to the original data output */
    newtermios.c_oflag &= ~OPOST;

    /* set input and output baudrate */
    if(serial->baudrate)
    {
        memset(setbaudrate,0,sizeof(setbaudrate));
        snprintf(setbaudrate,sizeof(setbaudrate),"B%d",serial->baudrate);
        cfsetispeed(&newtermios,(speed_t)setbaudrate);
        cfsetospeed(&newtermios,(speed_t)setbaudrate);
    }
    else
    {
        cfsetispeed(&newtermios,B115200);
        cfsetospeed(&newtermios,B115200);
    }

    /* set databits */
    switch(serial->databits)
    {
        case '5': newtermios.c_cflag |= CS5; break;
        case '6': newtermios.c_cflag |= CS6; break;
        case '7': newtermios.c_cflag |= CS7; break;
        case '8': newtermios.c_cflag |= CS8; break;
        default:  newtermios.c_cflag |= CS8; break; //default databits
    }

    /* parity bit */
    switch(serial->parity)
    {
        /* even parity */
        case 0: 
            newtermios.c_cflag |= PARENB;
            newtermios.c_cflag &= ~PARODD;
            newtermios.c_iflag |= INPCK;
            break;

        /* odd parity */
        case 1:
            newtermios.c_cflag |= PARENB;
            newtermios.c_cflag |= PARODD;
            newtermios.c_iflag |= INPCK;
            break;
        
        /* default no parity */
        default:
            newtermios.c_cflag &= ~PARENB;
            newtermios.c_iflag &= ~INPCK;
            break;
    }

    /* set stopbits */
    switch(serial->stopbits)
    {
        case 1: newtermios.c_cflag &= ~CSTOPB; break;
        case 2: newtermios.c_cflag |= CSTOPB; break;
        default: newtermios.c_cflag &= ~CSTOPB; break;
    }

    newtermios.c_cc[VTIME] = 0;     //Maximum waiting time
    newtermios.c_cc[VMIN] = 0;      //Minimum received character


    if(tcflush(serial->fd,TCIFLUSH) < 0)
    {
        printf("flush input queue failure: %s\n",strerror(errno));
        return -4;
    }

    /* set serial port property */
    if(tcsetattr(serial->fd,TCSANOW,&newtermios) < 0)
    {
        printf("set serial port property failure: %s\n",strerror(errno));
        return -5;
    }

    printf("--------------   serial port init successfully   ---------------\n");

    return 0;
}

3.2.4 serialinit.h

#ifndef  _SERIALINIT_H_
#define  _SERIALINIT_H_

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

typedef struct serial_ctx_s
{
    int             fd;  //serial fd
    char            serialname[128];
    int             baudrate;
    int             databits;
    int             parity;
    int             stopbits;
    struct termios  oldtermios; //the original properties of the serial port
}serial_ctx_t;


int serial_open(serial_ctx_t *serial);
int serial_close(serial_ctx_t *serial);
int serial_init(serial_ctx_t *serial);

#endif   /* ----- #ifndef _COMPORTINIT_H_  ----- */

3.2.5 serialswap.c

对串口设备文件进行I/O操作,主要功能:实现串口的发送和接收数据

#include "serialswap.h"

int serial_send(char *send_buf,serial_ctx_t serial,int send_len)
{
    char    *ptr,*end;
    int     rv = 0;

    if(!send_buf || send_len <= 0)
    {
        printf("%s,Invalid input arguments\n",__func__);
        return -1;
    }

    if(send_len > SEND_BUF)
    {
        ptr = send_buf;
        end = send_buf + send_len;

        do
        {
            if(SEND_BUF < (end - ptr))
            {
                rv = write(serial.fd,ptr,SEND_BUF);
                if(rv <= 0 || rv != SEND_BUF)
                {
                    printf("Write to serial port failure: %s\n",strerror(errno));
                    return -2;
                }

                ptr += SEND_BUF;
            }
            else
            {
                rv = write(serial.fd,ptr,(end - ptr));
                if(rv <= 0 || rv != (end - ptr))
                {
                    printf("Write to serial port failure: %s\n",strerror(errno));
                    return -3;
                }

                ptr += (end - ptr);
            }
        }while(end > ptr);
    }
    else
    {
        rv = write(serial.fd,send_buf,send_len);
        if(rv <= 0 || rv != send_len)
        {
            printf("Write to serial port failure: %s\n",strerror(errno));
            return -4;            
        }
    }

    return 0;
}

int serial_rece(char *rece_buf,serial_ctx_t serial,int rece_len,int timeout)
{
    int             rv = 0;
    fd_set          rdfds;
    struct timeval  time_out;

    if(!rece_buf || rece_buf <= 0)
    {
        printf("%s,Invalid input arguments\n",__func__);
        return -1;        
    }

    if(timeout)
    {
        time_out.tv_sec = (time_t)(timeout / 1000);
        time_out.tv_usec = 0;

        FD_ZERO(&rdfds);
        FD_SET(serial.fd,&rdfds);

        rv = select(serial.fd + 1,&rdfds,NULL,NULL,&time_out);
        if(rv < 0)
        {
            printf("select() serial post failure: %s\n",strerror(errno));
            return -2;
        }
        else if(0 == rv)
        {
            printf("select() serial post get timeout\n");  
            return -3;         
        }
    }

    usleep(1000);

    rv = read(serial.fd,rece_buf,rece_len);
    if(rv <= 0)
    {
        printf("Read serial port data failure: %s\n",strerror(errno));
        return -4;
    }
    
    return 0;
}

3.2.6 serialswap.h

#ifndef  _SERIALSWAP_H_
#define  _SERIALSWAP_H_

#include <sys/select.h>
#include "serialinit.h"

#define SEND_BUF    128

int serial_send(char *send_buf,serial_ctx_t serial,int send_len);
int serial_rece(char *rece_buf,serial_ctx_t serial,int rece_len,int timeout);

#endif   /* ----- #ifndef _SERIALSWAP_H_  ----- */

运行结果图:
在这里插入图片描述

4. 总结

1、以上代码只是实现类似minicom串口调式工具的其中的功能,只能实现串口AT指令的发送,并不能只实现发送和接收短信功能,后期会继续完善
2、用fgets()获取标准输入的字符串时,得到的字符串结尾会带上换行符"\n",所以要把’\n" 换成AT指令指定的结尾格式’\r".

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Linux中,删除字符的命令有多种,以下是其中几种常用的: 1. backspace键:在终端中输入字符时,可以使用backspace键删除光标前面的一个字符。 2. delete键:在终端中输入字符时,可以使用delete键删除光标后面的一个字符。 3. Ctrl+D:在终端中输入字符时,可以使用Ctrl+D删除光标所在位置的字符。 4. Ctrl+H:在终端中输入字符时,可以使用Ctrl+H删除光标前面的一个字符。 5. Ctrl+W:在终端中输入字符时,可以使用Ctrl+W删除光标前面的一个单词。 6. Ctrl+U:在终端中输入字符时,可以使用Ctrl+U删除光标前面的所有字符。 以上是常用的Linux删除字符的命令,可以根据需要选择使用。 ### 回答2: Linux系统中,删除字符命令是常见的操作之一。删除字符有多种方式,可以使用键盘快捷键和命令行工具。下面将介绍几种常用的方法。 1. 使用快捷键 在Linux系统中,使用Backspace或Delete键可以删除一个字符。当Delete键被按下时,光标后面的字符将被删除。当Backspace键被按下时,光标前面的字符将被删除。 2. 使用命令行 除了通过键盘快捷键删除字符,还可以通过命令行工具删除字符。命令行中最常用的删除字符命令是“backspace”、“delete”、“ctrl+h”、“ctrl+d”。 a. backspace命令:该命令要求在命令行上键入字符,并将光标移动到要删除的字符之前。然后,按下backspace键将删除该字符。 b. delete命令:该命令要求在命令行上键入字符,并将光标移动到要删除的字符之后。然后,按下delete键将删除该字符。 c. ctrl+h命令:该命令是一个跨平台的删除字符命令,可以在Linux、Windows、Mac OS等系统中使用。在命令行上键入ctrl+h,将删除光标前面的一个字符。 d. ctrl+d命令:该命令作用不是删除单个字符,而是结束当前进程。在命令行中按下ctrl+d,会终止当前进程或shell。 总的来说,在Linux系统中删除字符是非常简单的。在日常使用中,可以根据个人习惯和实际需求选择最适合自己的方式来删除字符。 ### 回答3: 在Linux中,有多种命令可以用来删除字符,下面我们来介绍几种常用的命令: 1. Backspace键 在Linux终端中,Backspace键是一个常用的删除字符命令,用来删除光标左侧的字符。 例如,如果你不小心输错了一个命令或者想要删除一些无用的文本,可以使用Backspace键删除。但需要注意的是,Backspace键只能删除光标前面的字符,如果你需要删除光标后面的字符,可以使用其他命令。 2. Delete键 Delete键和Backspace键正好相反,它用来删除光标右侧的字符。如果你想要删除某个词或者一段文本的最后一个字符,可以使用Delete键。 需要注意的是,Delete键只能删除光标后面的字符,如果需要删除光标前面的字符,可以使用其他命令。 3. Ctrl + D Ctrl + D命令可以用来删除光标所在位置的字符,它相当于在当前位置敲入了一个EOF(End Of File)字符。当你使用Ctrl + D命令时,如果光标在最后一行的最后一个字符后面,它会结束当前的输入并关闭终端。 需要注意的是,Ctrl + D无法删除光标前面的字符。 4. Ctrl + U Ctrl + U命令可以用来删除当前光标前面的所有字符,它相当于从当前光标位置向前删掉所有的字符。 例如,如果你需要重新输入一个命令或修改一段文本,可以使用Ctrl + U命令将光标前面的所有文本删除。 5. Ctrl + K Ctrl + K命令可以用来删除当前光标后面的所有字符,它相当于将当前光标位置及以后的所有字符删除。 例如,如果你需要删除一段无用的文本或者重新输入一段文本,可以使用Ctrl + K命令删除当前光标及以后的所有文本。 总之,Linux中有多种命令可以用来删除字符,每种命令都有各自的用途和场景。在实际应用中,我们需要根据需求选择最合适的命令来完成字符删除操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值