当前位置:首页 » 编程软件 » shell编程教程

shell编程教程

发布时间: 2023-01-29 03:43:53

A. 简单的shell编程

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>

#define BUFFERSIZE 80

extern char *get_current_dir_name(void);
extern char *getenv(const char *name);
extern pid_t waitpid(pid_t pid, int *status, int options);

char buffer[BUFFERSIZE+1];

main()
{
char *path, *arg[10], *input;
int li_inputlen, is_bj, is_back, i, j, k, pid, status;
char lc_char;

while (1){
/* initiations */
is_bj = 0; /*redirection flag*/
is_back = 0; /*background*/

/* shell prompt */
path = get_current_dir_name();
printf("%s>$",path);

/*开始获取输入*/
li_inputlen = 0;
lc_char = getchar();
while (lc_char !='\n'){
if(li_inputlen < BUFFERSIZE)
buffer[li_inputlen++] = lc_char;
lc_char = getchar();
}

/*命令超长处理*/
if (li_inputlen >= BUFFERSIZE){
printf("Your command is too long! Please re-enter your command!\n");
li_inputlen = 0; /*reset */
continue;
}
else
buffer[li_inputlen] = '\0';/*加上串结束符号,形成字串*/

/*将命令从缓存拷贝到input中*/
input = (char *) malloc(sizeof(char) * (li_inputlen+1));
strcpy(input,buffer);

/* 获取命令和参数并保存在arg中*/
for (i = 0,j = 0,k = 0;i <= li_inputlen;i++){
/*管道和重定向单独处理*/
if (input[i] == '<' || input[i] == '>' || input[i] =='|'){
if (input[i] == '|')
pipel(input,li_inputlen);
else
redirect(input,li_inputlen);
is_bj = 1;
break;
}
/*处理空格、TAB和结束符。不用处理‘\n',大家如果仔细分析前面的获取输入的程序的话,
*不难发现回车符并没有写入buffer*/
if (input[i] == ' ' || input[i] =='\t' || input[i] == '\0'){
if (j == 0) /*这个条件可以略去连在一起的多个空格或者tab*/
continue;
else{
buffer[j++] = '\0';
arg[k] = (char *) malloc(sizeof(char)*j);
/*将指令或参数从缓存拷贝到arg中*/
strcpy(arg[k],buffer);
j = 0; /*准备取下一个参数*/
k++;
}
}
else{
/*如果字串最后是‘&',则置后台运行标记为1*/
if (input[i] == '&' && input[i+1] == '\0'){
is_back = 1;
continue;
}
buffer[j++] = input[i];
}
}

free(input);/*释放空间*/

/*如果输入的指令是leave则退出while,即退出程序*/
if (strcmp(arg[0],"leave") == 0 ){
printf("bye-bye\n");
break;
}
/*如果输入的指令是about则显示作者信息,同时结束本条命令的解析过程*/
if (strcmp(arg[0]," about") == 0 ){
printf("right by shike,[email protected]\n");
continue;
}

if (is_bj == 0){ /*非管道、重定向指令*/
/*在使用xxec执行命令的时候,最后的参数必须是NULL指针,
*所以将最后一个参数置成空值*/
arg[k] = (char *) 0;
/*判断指令arg[0]是否存在*/
if (is_fileexist(arg[0]) == -1 ){
printf("This command is not found?!\n");
for(i=0;i<k;i++)
free(arg[i]);
continue;
}

/* fork a sub-process to run the execution file */
if ((pid = fork()) ==0) /*子进程*/
execv(buffer,arg);
else /*父进程*/
if (is_back == 0) /*并非后台执行指令*/
waitpid(pid,&status,0);

/*释放申请的空间*/
for (i=0;i<k;i++)
free(arg[i]);
}
}
}

int is_fileexist(char *comm)
{
char *path,*p;
int i;

i = 0;
/*使用getenv函数来获取系统环境变量,用参数PATH表示获取路径*/
path = getenv("PATH");
p = path;
while (*p != '\0'){
/*路径列表使用‘:’来分隔路径*/
if (*p != ':')
buffer[i++] = *p;
else{
buffer[i++] = '/';
buffer[i] = '\0';
/*将指令和路径合成,形成pathname,并使用access函数来判断该文件是否存在*/
strcat(buffer,comm);

if (access(buffer,F_OK) == 0) /*文件被找到*/
return 0;
else
/*继续寻找其它路径*/
i = 0;
}
p++;
}
/*搜索完所有路径,依然没有找到则返回-1*/
return -1;
}

int redirect(char *in,int len)
{
char *argv[30],*filename[2];
pid_t pid;
int i,j,k,fd_in,fd_out,is_in = -1,is_out = -1,num = 0;
int is_back = 0,status=0;

/*这里是重定向的命令解析过程,其中filename用于存放重定向文件,
*is_in, is_out分别是输入重定向标记和输出重定向标记*/
for (i = 0,j = 0,k = 0;i <= len;i++){
if (in[i]==' '||in[i]=='\t'||in[i]=='\0'||in[i] =='<'||in[i]=='>'){
if (in[i] == '>' || in[i] == '<'){
/*重定向指令最多'<','>'各出现一次,因此num最大为2,
*否则认为命令输入错误*/
if (num < 3){
num ++;
if (in[i] == '<')
is_in = num - 1;
else
is_out = num - 1;

/*处理命令和重定向符号相连的情况,比如ls>a*/
if (j > 0 && num == 1) {
buffer[j++] = '\0';
argv[k] = (char *) malloc(sizeof(char)*j);
strcpy(argv[k],buffer);
k++;
j = 0;
}
}
else{
printf("The format is error!\n");
return -1;
}
}
if (j == 0)
continue;
else{
buffer[j++] = '\0';
/*尚未遇到重定向符号,字符串是命令或参数*/
if (num == 0){
argv[k] = (char *) malloc(sizeof(char)*j);
strcpy(argv[k],buffer);
k++;
}
/*是重定向后符号的字符串,是文件名*/
else{
filename[status] = (char *) malloc(sizeof(char)*j);
strcpy(filename[status++],buffer);
}
j = 0; /*initate*/
}
}
else{
if (in[i] == '&' && in[i+1] == '\0'){
is_back = 1;
continue;
}
buffer[j++] = in[i];
}
}

argv[k] = (char *) 0;

if (is_fileexist(argv[0]) == -1 ){
printf("This command is not founded!\n");
for(i=0;i<k;i++)
free(argv[i]);
return 0;
}

if ((pid = fork()) ==0){
/*存在输出重定向*/
if (is_out != -1)
if((fd_out=open(filename[is_out],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1){
printf("Open out %s Error\n",filename[is_out]);
return -1;
}

/*存在输入重定向*/
if (is_in != -1)
if((fd_in=open(filename[is_in],O_RDONLY,S_IRUSR|S_IWUSR))==-1){
printf("Open in %s Error\n",filename[is_out]);
return -1;
}

if (is_out != -1)
/*使用p2函数将标准输出重定向到fd_out上,p2(int oldfd,int newfd)实现的
*是把oldfd所指的文件描述符复制到newfd。若newfd为一已打开的文件描述词,
*则newfd所指的文件会先被关闭,p2复制的文件描述词与原来的文件描述词
*共享各种文件状态*/
if(p2(fd_out,STDOUT_FILENO)==-1){
printf("Redirect Standard Out Error\n");
exit(1);
}

if (is_in != -1)
if(p2(fd_in,STDIN_FILENO)==-1){
printf("Redirect Standard Out Error\n");
exit(1);
}
execv(buffer,argv);
}
else
if (is_back == 0) /*run on the TOP*/
waitpid(pid,&status,0);

for (i=0;i<k;i++)
free(argv[i]);

if (is_in != -1){
free(filename[is_in]);
close(fd_in);
}
if (is_out != -1){
free(filename[is_out]);
close(fd_out);
}
return 0;
}

int pipel(char *input,int len)
{
char *argv[2][30];
int i,j,k,count,is_back = 0;
int li_comm = 0,fd[2],fpip[2];
char lc_char,lc_end[1];
pid_t child1,child2;

/*管道的命令解析过程*/
for (i = 0,j = 0,k = 0;i <= len;i++){
if (input[i]== ' ' || input[i] == '\t' || input[i] == '\0' || input[i] == '|'){
if (input[i] == '|' ) /*管道符号*/
{
if (j > 0)
{
buffer[j++] = '\0';
/*因为管道连接的是两个指令,所以用二维数组指针来存放命令和参数,
*li_comm是表示第几个指令*/
argv[li_comm][k] = (char *) malloc(sizeof(char)*j);
strcpy(argv[li_comm][k++],buffer);
}
argv[li_comm][k++] = (char *) 0;
/*遇到管道符,第一个指令完毕,开始准备接受第二个指令*/
li_comm++;
count = k;
k=0;j=0;
}
if (j == 0)
continue;
else
{
buffer[j++] = '\0';
argv[li_comm][k] = (char *) malloc(sizeof(char)*j);
strcpy(argv[li_comm][k],buffer);
k++;
}
j = 0; /*initate*/
}
else{
if (input[i] == '&' && input[i+1] == '\0'){
is_back = 1;
continue;
}
buffer[j++] = input[i];
}
}
argv[li_comm][k++] = (char *) 0;

if (is_fileexist(argv[0][0]) == -1 ){
printf("This first command is not found!\n");
for(i=0;i<count;i++)
free(argv[0][i]);
return 0;
}
/*指令解析结束*/

/*建立管道*/
if (pipe(fd) == -1 ){
printf("open pipe error!\n");
return -1;
}

/*创建第一个子进程执行管道符前的指令,并将输出写到管道*/
if ((child1 = fork()) ==0){
/*关闭读端*/
close(fd[0]);
if (fd[1] != STDOUT_FILENO){
/*将标准输出重定向到管道的写入端,这样该子进程的输出就写入了管道*/
if (p2(fd[1],STDOUT_FILENO) == -1){
printf("Redirect Standard Out Error\n");
return -1;
}
/*关闭写入端*/
close(fd[1]);
}
execv(buffer,argv[0]);
}
else{ /*父进程*/
/*先要等待写入管道的进程结束*/
waitpid(child1,&li_comm,0);
/*然后我们必须写入一个结束标记,告诉读管道进程数据到这里就完了*/
lc_end[0] = 0x1a;
write(fd[1],lc_end,1);
close(fd[1]);

if (is_fileexist(argv[1][0]) == -1 ){
printf("This command is not founded!\n");
for(i=0;i<k;i++)
free(argv[1][i]);
return 0;
}

/*创建第二个进程执行管道符后的指令,并从管道读输入流 */
if ((child2 = fork()) == 0){
if (fd[0] != STDIN_FILENO){
/*将标准输入重定向到管道读入端*/
if(p2(fd[0],STDIN_FILENO) == -1){
printf("Redirect Standard In Error!\n");
return -1;
}
close(fd[0]);
}
execv(buffer,argv[1]);
}
else /*父进程*/
if (is_back == 0)
waitpid(child2,NULL,0);
}
for (i=0;i<count;i++)
free(argv[0][i]);
for (i=0;i<k;i++)
free(argv[1][i]);
return 0;
}

以前写的,好像一些细节不一样,不明白的地方,发邮件给我,[email protected]

B. 《linux命令行与shell脚本编程大全》pdf下载在线阅读全文,求百度网盘云资源

《Linux命令行与shell脚本编程大全》网络网盘pdf最新全集下载:
链接: https://pan..com/s/1E_h5bBXPM-pZR2jFGctrgA

?pwd=33bh 提取码: 33bh
简介:这是一本关于Linux命令行与shell脚本编程的全方位教程,主要包括四大部分:Linux命令行,shell脚本编程基础,高级shell脚本编程,如何创建实用的shell脚本。本书针对Linux系统的新特性进行了全面更新,不仅涵盖了详尽的动手教程和现实世界中的实用信息,还提供了与所学内容相关的参考信息和背景资料。通过本书的学习,你将轻松写出自己的shell脚本。

C. shell脚本是什么

当执行命令或程序语句是通过程序文件而不是命令行,那这个程序被称为Shell脚本。如果Shell脚本内置很多命令、语句及循环控制,然后一次性执行完毕,这种通过文件执行脚本的方式称为非交互方式。用户可以在Shell脚本中输入一系列命令及命令语句组合。这些命令、变量和流程控制语句等有机地结合在一起,就形成一个功能强大的Shell脚本。

D. ‘Linux 干货’#1 终端与Shell(简明)

继 Git 后贵系的另一个暑培项目,讲授 Linux 的基本用法,恰好这学期“操作系统”课程实验需要用到 Linux,而且实验室的服务器也需要学习相关用法,故学之。

本文部分内容参考了清华 ZAH 同学的教程,部分参考了 刘遄 老师的《 Linux 就该这么学 》, 菜鸟教程-Linux 。

Linux,全称 GNU/Linux,是一套免费使用和自由传播的类 Unix 操作系统。相比于其他系统,Linux 更加稳定且有效率、更加安全、相对不耗资源……以至于几乎所有 长期稳定运行的网站服务器 上、在 处理大数据的集群系统 中,以及需要 协同工作的服务器环境 都采用 Linux 系统。

Linux 严格来说是单指操作系统的 内核 ,因操作系统中包含了许多用户图形接口和其他实用工具。如今 Linux 常用来指“基于 Linux 的完整操作系统”,内核则改以“Linux 内核”称之。

一些组织或厂商将 Linux 内核与各种软件和文档 包装 起来,并提供系统安装界面和系统配置、设定与管理工具,就构成了 Linux 的发行版本。

在学习 Linux 的过程中,有几个易混淆的概念:

命令行界面(Command-Line Interface,CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。也有人称之为字符用户界面(Character User Interface,CUI)。

一般来说,在 服务器 中较多采用的是 CLI 界面,或许有以下几点原因:

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 等系统的桥梁,如同“ ”一般。它的本质是一个 命令解释器 ,将用户输入的命令(符合 Shell 语法)处理成对应 操作系统的控制命令 ,处理完毕后再将结果反馈给用户。

不同操作系统下面的 Shell 种类众多,常见的有:

Ken Thompson 的 sh 是第一种 Unix Shell,本教程关注的是 Bash,也就是 Bourne Again Shell,Bash 也是大多数 Linux 系统默认的 Shell。

终端 (Terminal),是一种用来让用户输入数据至计算机,以及显示其计算结果的机器。早期的终端通常就是一台 电子打字机 (Teletypewriter, TTY),后来随着计算机的发展,打字机被键盘和显示器取代,而 GUI 界面也成了主流。

于是,这时候我们就需要一个程序来模拟传统终端的行为,即 终端模拟器 (Terminal Emulator),当用户打开终端模拟器时,实际上是进入一个 会话进程 (Session)。终端模拟器有很多,这里举几个经典的例子:

在 Linux 系统中打开终端时,会看到一个提示符,通常类似 hewei@hewei-VirtualBox ~$ 。在提示符下,命令会被 Shell 环境 解析并反馈 到终端中。

提示符是 Shell 最主要的 文本接口 。它告诉你,你的主机名是 hewei-VirtualBox ,你现在的身份是 hewei 并且你当前的 工作目录 (Current working directory)是 ~ (默认在 /home/hewei/ 用户目录)。

$ 符号表示您现在的身份不是 root ,输入如下命令可以暂时切换到 root 权限:

输入密码后,可以看到提示符变成了 root@hewei-VirtualBox:/home/hewei# ,其中 # 符号就是超级用户权限的标志。再输入 exit 即可退回普通用户身份。

在 Git学习笔记 #1 基础知识介绍 中,已经简单介绍了命令行界面的一些使用技巧,这些命令在 Linux 系统的 Bash 中同样使用。这里罗列出 Linux 常用快捷键:

常见的执行 Linux 命令的格式是这样的: 命令名称 [命令参数] [命令对象] 。其中,命令参数用于对命令进行调整,使之更好地贴近需求,参数分为 长格式 短格式 ,如: man --help , man -h 。短格式之间可以合并,合并后仅保留一个减号即可。

在 Linux 相关的手册中,我们会约定俗成地将可选择的、非必需的参数使用 中括号 引起来,而命令所要求的、必须有的参数或对象值,则不带中括号。

此外,要注意 Linux 系统中的命令、参数、对象都是 严格区分大小写 的。

Shell 除了是一个 交互式 (Interactive)的命令解释器,它还是一种 程序设计语言 (Shell Script)。它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。

用 Shell 编写的 脚本文件 即 .sh 文件,它能在 Shell 环境下运行,fork 出一个 子进程 ,调用系统内核来执行 批处理 (Batch)的系统控制。在文件的第一行,通常是 #!/bin/bash ,这句话约定了这个脚本需要哪种 Shell 环境来执行。

通过如下命令就可以执行一个 Shell 脚本:

下面罗列了部分常用指令与参数的介绍,更多功能请在帮助手册中检索。

E. 学生信的那些事儿之七 - Linux基础之Shell脚本编程

沿着前面的轨迹,接下来是Linux中shell脚本的学习。这对于生信工程师后续处理大量 (海量更合适些) 数据是非常非常重要的,但是同样的,作为一个有点古板的人,对于"脚本"是什么意思我都死磕了好久。主要觉得有些抽象,尤其是跟生信的同事讨论项目分析部分的问题时,他们经常会说道这个词,在他们意识里这是个不言自明的术语,殊不知对外行人而言 (比如我),那简直就是无情的"知识的诅咒"。经常是我假装听懂了,然后继续讨论下面的问题,形成一个模糊的印象。

网络上的解释是:脚本(Script)是一种批处理文件的延伸,是一种纯文本保存的程序,一般来说的计算机脚本程序是确定的一系列控制计算机进行运算操作动作的组合,在其中可以实现一定的逻辑分支等。不知道你能不能看懂,反正我开始的时候真是一知半解。

鸟哥私房菜的解释是:shell script是利用 shell 的功能所写的一个"程序",这个程序是使用纯文本文件,将一些shell的语法与命令(含外部命令)写在里面,搭配正则表达式、管道命令与数据流重定向等功能,以达到我们所想要的处理的目的。不明觉厉,好像更看不懂了···

Jude 的简单粗暴大白话解释是:脚本就是Linux中很多命令按照一定规则的组合,以实现某个特定的功能。Linux中有很多简单的命令,往往只是进行了简单的对话,比如 cd 就是进入到某个目录,简单直接。但是如果我想进入某个目录A,然后在目录A中创建目录B,再在目录B中创建文本C呢?当然可以一步一步操作,如果想要一步到位呢,那就可以用脚本,把三个命令写在一起,一起执行。好像有点啰嗦···

或者从英语的角度去理解,脚本的对应英文是Script,而这个单词的中文释义中还有剧本的意思。剧本就好理解了啊,剧本就是导演(生信工程师)基于某个主旨(要实现的目标)按照一定的手法(规则)所写的一个故事。不管是哪个演员,都得按照剧本演。所以,学好英语对于生信也是有帮助的~

按照脚本的复杂程度可以分为:

这个无需多说,其实就是若干个简单命令的顺序排列,执行脚本后会按照命令的前后关系从前往后一一执行。

相对于简单的基本脚本,结构化的命令脚本可以施加逻辑流程控制,从而改变程序(命令)执行的顺序。基本脚本中的命令就是从上往下执行,但是结构化的命令脚本可以根据逻辑判断重复或者跳过某些命令。

常用的结构化命令(语句)有:

后面还有什么嵌套循环啊啥的,不过我觉得上面的7中命令学到家了,应该可以应付大部分在生信分析里面的应用了。

记得高中的时候,物理老师(也是班主任)在给我们讲解习题时有个有意思的套路:不管什么难题现在下面写个"答:",以示自己解决问题的决心,也是一种正向的心理暗示。脚本编写也是有套路的,不过总的来说还是比较简单。

对于简单的脚本(超级简单的那种),直接几个命令连在一起即可,中间用";"隔开。

对于更长更复杂的脚本,一般需要创建一个文本,并在里面编辑。这就涉及到了文本编辑器,比较常用和简单的一般有nano和vim,实在很简单,规则也容易理解,教程随手可得,不多说。

比如用vim创建了一个脚本之后,具体的语法(套路):

ok,脚本写完了,怎么让脚本开始工作呢?这有涉及到之前讲过的环境变量和相对路径、绝对路径了。方法有三:

就这么多吧,应该有点感觉到了,剩下的就是狂练狂练了~

F. Linux Shell 教程——想玩转linux就请一直看下去

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。

Shell 在线工具

Shell 脚本(shell script),是一种为 shell 编写的脚本程序。

业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。

由于习惯的原因,简洁起见,本文出现的 "shell编程" 都是指 shell 脚本编程,不是指开发 shell 自身。

Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。

Linux 的 Shell 种类众多,常见的有:

在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh ,它同样也可以改为 #!/bin/bash

#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。

打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用 php 写 shell 脚本,扩展名就用 php 好了。

输入一些代码,第一行一般是这样:

#!/bin/bash
echo "Hello World !"


运行实例 »

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。

echo 命令用于向窗口输出文本。

1、作为可执行程序

将上面的代码保存为 test.sh,并 cd 到相应目录:

注意,一定要写成 ./test.sh ,而不是 test.sh ,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。

2、作为解释器参数

这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如:

这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。

热点内容
java返回this 发布:2025-10-20 08:28:16 浏览:710
制作脚本网站 发布:2025-10-20 08:17:34 浏览:973
python中的init方法 发布:2025-10-20 08:17:33 浏览:684
图案密码什么意思 发布:2025-10-20 08:16:56 浏览:836
怎么清理微信视频缓存 发布:2025-10-20 08:12:37 浏览:742
c语言编译器怎么看执行过程 发布:2025-10-20 08:00:32 浏览:1083
邮箱如何填写发信服务器 发布:2025-10-20 07:45:27 浏览:313
shell脚本入门案例 发布:2025-10-20 07:44:45 浏览:193
怎么上传照片浏览上传 发布:2025-10-20 07:44:03 浏览:881
python股票数据获取 发布:2025-10-20 07:39:44 浏览:839