Linux的编程问题!编写一个shell脚本它把第二个位置参数及其以后的各个参数指定的文件复制
您好,这是您问题的解决方案。编写一个shell脚本来复制第二个位置参数和每个后续参数指定的文件。
具体来说,该脚本的作用是将这些文件复制到指定目录并列出复制的文件。
首先,我们需要定义一个变量来存储复制文件的路径。
这是第一个参数,如下所示:dir=$1。
那么,如果使用shift命令将参数前移,$1的值就变成了$2,原来的$1已经不存在了。
同样,$2的值变为$3,依此类推。
如果原来有9个参数,经过移位后只剩下8个。
然后使用while循环处理剩余的参数,直到处理完所有参数。
在这个循环中,可以通过file=$1将当前参数赋给一个文件变量。
然后使用cp命令将文件复制到指定目录(cp$file$dir)。
文件复制完成后,再次使用shift命令前进参数,直到处理完所有参数。
处理完所有参数后,您可以使用ls命令列出复制的文件(ls$dir)。
现在整个shell脚本已经写好了。
如果您觉得本回答对您有帮助,请不要忘记采纳。
此外,如果您想了解有关shell编程的更多信息,我强烈建议您阅读《ThisisHowYouShouldLearnLinux》一书。
本书的学习路径比较系统、轻松,非常适合初学者。

怎么写LINUX的SHELL?
测试Linux时编写脚本至关重要。shell脚本名可以任意设置,不带任何后缀。
例如,您可以编写abc和smartzip之类的名称。
运行时,只需键入./smartzip即可运行脚本。
。
每个命令行开头是否没有空格并不重要。
。
第1部分Linux脚本基础知识1.1基本语法介绍1.1.1程序必须以下行开始(必须位于文件的第一行):#!/bin/sh符号#!system下面的参数是用来执行该文件的程序。
在本例中,我们使用/bin/sh来运行程序。
编辑脚本时,如果要运行该脚本,还必须使其可执行。
要使脚本可执行:编译chmod+xfilename,以便可以使用./filename运行它1.1.2注释在shell中编程时,以#开头的句子表示注释,直到行尾。
我们真诚地建议您在程序中使用注释。
如果使用注释,即使您很长时间没有使用该脚本,也可以在短时间内了解该脚本的作用和工作原理。
1.1.3变量在其他编程语言中,必须使用变量。
在shell编程中,所有变量都是由字符串组成的,你不需要声明任何变量。
给变量赋值可以这样写:#!/bin/sh#给变量赋值:a="helloworld"#现在打印变量a的内容:echo"Ais:"echo$a有时变量名很容易匹配。
其他文本则令人困惑,例如:num=2echo"thisisthe$numnd"这不会打印“thisisthe2nd”,而只会打印“thisisthe”,因为shell会查找变量的值。
numnd,但是这个变量没有值。
可以用大括号告诉shell我们要打印的是变量num:num=2echo"thisisthe${num}nd"这会打印:thisisthe2nd1.1.4环境变量通过export关键字处理的变量称为环境变量。
。
我们不会讨论环境变量,因为它们通常只在登录脚本中使用。
1.1.5Shell命令和进程控制shell脚本中可以使用三种类型的命令:1)Unix命令:虽然任何Unix命令都可以在Shell脚本中使用,但仍然有一些命令相对更常用。
这些命令一般用于文件和文本操作。
语法及常用命令功能echo"sometext":在屏幕上显示文本内容ls:文件列表wc–lfile:统计文件中的行数wc-wfile:统计wc文件中的单词数-cfile:计算文件中的字符数cpsourcefiledestfile:复制文件mvoldnamenewname:重命名文件或移动文件rmfile:删除文件grep'pattern'file:搜索文件搜索字符串,例如:grep'searchstring'file.txt;cut-bcolnumfile:指定要显示的文件内容范围,并将其发送到标准输出设备。
例如:显示每条折线的第5到第9个字符。
b5-9file.txt不应与cat命令混淆。
这是两个完全不同的命令catfile.txt:将文件内容显示到标准输出设备(屏幕)filesomefile:获取文件类型readv。
ar:提示用户输入并分配变量sortfile.txt的输入:对文件file.txt中的行进行排序uniq:删除文本文件中出现的行和列。
例如:sortfile.txt|uniqexpr。
:进行数学运算例:add2and3expr2"+"3search:搜索文件例如:根据文件名搜索find.-namefilename-printtee:导出数据到标准输出设备(.screen)和文件如:somecommand|teeoutfilebasenamefile:返回不带路径的文件名例如:basename/bin/tux将返回tuxdirnamefile:返回文件路径。
返回/bin。
headfile:打印文本文件tailfile的前几行:打印文本文件的最后几行sed:Sed是一个基本的查找和替换程序。
您可以从标准输入(例如命令通道)读取文本并将结果显示到标准输出(屏幕)。
该命令使用正则表达式(请参阅参考资料)进行搜索。
不要与shell中的通配符混淆。
例如:将Linuxfocus替换为LinuxFocus:cattext.file|sed's/linuxfocus/LinuxFocus/'>newtext.file awk:awk用于从文本文件中提取字段。
默认情况下,字段分隔符是空格。
您可以使用-F指定其他分隔符。
catfile.txt|awk-F,'{print$1","$3}'这里我们使用作为字段分隔符来同时打印第一个和第三个字段。
如果文件内容为:AdamBor,34,IndiaKerryMiller,22,USA,则命令的结果为:AdamBor,IndiaKerryMiller,USA2)概念:管道、重定向和反引号这些不是系统命令,但它们确实很重要。
管道(|)使用一个命令的输出作为另一命令的输入。
grep"你好"file.txt|wc-l在file.txt中查找包含“hello”的行并计算行数。
这里,grep命令的输出用作wc命令的输入。
当然,您可以使用多个命令。
重定向:将命令结果显示到文件而不是标准(屏幕)输出。
>写入文件并覆盖旧文件>>>追加到文件末尾,保留旧文件的内容。
反斜杠使用反斜杠将一个命令的结果作为命令行参数传递给另一个命令。
命令:find.-mtime-1-typef-print用于查找最近24小时内修改的文件(-mtime–2表示最近48小时)。
如果要将找到的所有文件分组,可以使用以下脚本:#!/bin/sh#Theticksarebackticks(`)notnormalquotes('):tar-zcvflastmod.tar.gz`find.-mtime-1-typef-print`3)流程控制1.if表达式“if”如果条件为真,则执行then后面的部分:if......;then......elif......;then......else....fi在大多数情况下,可以使用测试命令来测试条件。
例如,您可以比较字符串、确定文件是否存在并且可读等等...通常使用“[]”来表示条件测试。
请注意,这里的空格很重要。
确保括号之间有空格。
[-f"somefile"]:确定这是否是一个文件[-x"/bin/ls"]:确定/bin/ls是否存在并具有可执行权限[-n"$var"]:确定$var是否存在变量有一个值["$a"="$b"]:判断$a和$b是否相等。
运行mantest,显示所有可以通过测试表达式进行比较判断的类型。
直接运行以下脚本:#!/bin/shif["$SHELL"="/bin/bash"];然后echo"yourloginshellisthebash(bourneagainshell)"elseecho"yourloginshellisnotbashbut$SHELL"fi$SHELL变量包含登录shell的名称,我们与/bin/bash进行比较。
快捷操作符熟悉C语言的朋友可能喜欢下面的表达式:[-f"/etc/shadow"]&&echo"Thiscomputerusesshadowpasswords"这里&&是快捷操作符。
如果左边的表达式为真,则右边的表达式也为真。
语句执行。
你也可以把它想象成逻辑运算中的AND运算。
上面的示例表明,如果/etc/shadow文件存在,则会打印“Thiscomputerusesshadowpasswords”。
在shell编程中也可以使用相同的OR(||)运算。
下面是一个示例:#!/bin/shmailfolder=/var/spool/mail/james[-r"$mailfolder"]''{echo"Cannotread$mailfolder";exit1;}echo"$mailfolderhasmailfrom:"grep"^From"$mailfolder脚本首先判断邮件文件夹是否可读。
如果可读,则打印文件中的“From”行。
如果不可读,则OR运算生效,脚本在打印错误消息后退出。
这里有一个问题,就是我们需要有两个命令:-打印错误信息-退出程序我们用大括号将这两个命令组合成一个命令,作为匿名函数。
一般功能如下所述。
我们还可以使用if表达式在没有AND或运算符的情况下执行任何操作,但使用AND或运算符要方便得多。
2.casecase:表达式可以用来匹配给定的字符串而不是数字。
case...in...)dosomethinghere;;esac让我们看一个例子。
file命令可以识别给定文件的文件类型,例如:filef.gz。
这将返回:lf.gz:gzipcompresseddata,deflated,originalfilename,lastmodified:MonAug2723:09.:182001,os:Unix我们利用这一点编写了一个名为smartzip的脚本,它可以自动解压缩bzip2、gzip和类型的压缩文件zip:#!/bin/shftype=`文件"$1"`案例"$ftype""$1:Ziparchive"*) unzip"$1";;"$1:gzipcompressed"*) gunzip"$1";;"$1:bzip2compressed"*) bunzip2"$1";;*)echo"文件$1无法使用smartzip解压缩";;esac 你可能会注意到我们使用了一个特殊变量$1这里。
该变量包含传递给程序的第一个参数的值。
也就是说,当我们运行:smartziarticles.zip$1是字符串articles.zip3.selsectselect表达式是一个bash扩展应用程序,特别适合交互式使用。
用户可以从一组不同的值中进行选择。
selectvarin...;dobreakdone....现在$var可以使用...这里有一个示例:#!/bin/shecho"WhatisyourfavouriteOS?"selectvarin"Linux""GnuHurd""FreeBSD""Other";dobreakdoneecho"Youaveselected$var"这是运行此脚本的结果:您的操作系统是什么首选?1)Linux2)GnuHurd3)FreeBSD4)其他#?1您已选择Linux4.loop循环表达式:while...;do....donewhile循环将一直运行,直到表达式测试为真。
只要我们测试的表达式为真就会运行。
“break”关键字用于跳出循环。
“Continue”关键字允许您直接进入下一个循环,而不执行剩余部分。
for循环表达式查看字符串列表(以空格分隔的字符串)并将其分配给变量:forvarin....;do<....done在下面的示例中,分别在屏幕上打印ABC:#!/bin/shforvarinABC;doecho"varis$var"done下面是一个比较有用的showrpm脚本,其作用是打印信息RPM软件包统计信息:#!/bin/sh#listacontentsummaryoanumberofRPMpackages#USAGE:showrpmrpmfile1rpmfile2...#EXAMPLE:showrpm/cdrom/RedHat/RPMS/*.rpmforrpmpackagein$*;doif[-r"$rpmpackage"];“=================$rpmpackagee=============="rpm-qi-p$rpmpackageelse输入的命令行参数的值。
如果运行showrpmopenssh.rpmw3m.rpmwebgrep.rpm则$*包含3个字符串,即openssh.rpm、w3m.rpm和webgrep.rpm.5引号程序在将参数传递给程序之前会扩展通配符和变量。
这里所谓的扩展是指程序将通配符(如*)替换为适当的文件名,并将其他变量替换为变量值。
为了防止程序进行这种替换,可以使用引号:让我们看一个例子,假设当前目录中有文件,两个jpg文件,mail.jpg和tux.jpg。
1.2慢慢编译SHELL脚本#ch#!/bin/shmod+xfilename
引号(单引号和双引号)将阻止这种通配符扩展:#!/bin/shecho"*.jpg"echo'*.jpg'这将打印“*.jpg”两次。
单引号的限制性更强。
它可以防止任何变量扩展。
双引号可防止通配符扩展,但允许变量扩展。
#!/bin/shecho$SHELLecho"$SHELL"echo'$SHELL'结果是:/bin/bash/bin/bash$SHELL最后还有一个方法可以防止这种扩展,那就是使用字符排气——Backslope:echo/*.jpgecho/$SHELL这将打印:*.jpg$SHELL6.Heredocuments当将多行文本传递给命令时,heredocuments(注释来自译者:我还没有看到这个词的正确翻译)这不是一个坏方法。
它有助于为每个脚本编写有用的文本。
现在,如果我们这里有文档,我们就不需要使用echo函数来逐行显示。
“Heredocument”是一个特殊用途的代码块。
它使用I/O重定向将一系列命令传递给交互式程序或命令,例如ftp、cat或ex文本编辑器1COMMA。
NDlimitstring用于限制命令序列的范围(译者注:有一个命令序列两个相同的限制链之间)。
特殊符号和本文档的形式如下:1#!/bin/bash2interactive-program选择一项。
名称很奇怪的限制链将避免命令列表和限制链同名的问题。
下面是一个例子。
,我们重命名几个文件,并使用这里的文档来打印帮助:#!/bin/sh#wehavelessthan3arguments.Printthehelptext:if[$#-lt3];thencat4)函数如果你编写稍微复杂一点的程序,你会发现相同的代码可以在程序中的多个地方使用,而且你还会发现如果我们使用函数会方便得多。
函数如下所示:functionname(){#insidethebody$1isthefirstargumentgiventothefunction#$2thesecond...body}您必须在每个程序的开头声明该函数。
下面是一个名为xtitlebar的脚本,使用该脚本您可以更改终端窗口名称。
这里使用了一个名为help的函数。
正如您所看到的,这个定义的函数被使用了两次。
#!/bin/sh#vim:setsw=4ts=4et:help(){catshiftby2--)shift;break;;#endofoptions-*)echo"error:nosuchoption$1.-hforhelp";exit1;; *)break;;esacdoneecho"opt_fis$opt_f"echo"opt_lis$opt_l"echo"firstargis$1"echo"2ndargis$2"您可以像这样运行脚本:cmdparser-lhello-f---somefile1somefile2返回的结果是:opt_fis1opt_lihellofirstargis-somefile12ndargissomefile2该脚本如何工作?该脚本首先循环遍历所有输入的命令行参数,将输入参数与case表达式进行比较,设置一个变量,如果匹配则删除该参数。
根据Unix系统的约定,第一个条目必须是包含减号的参数。
第二部分的例子。
我们现在将讨论编写脚本的一般步骤。
任何好的脚本都应该有帮助和输入参数。
编写一个包含大多数脚本所需的框架结构的伪脚本(framework.sh)是一个非常好的主意。
此时,在编写新脚本时,只需运行复制命令:cpframework.shmyscript,然后插入我们自己的函数。
我们再看两个例子:(1)二进制到十进制的转换b2d脚本将二进制数(如1101)转换为相应的十进制数。
这也是使用expr命令执行数学运算的示例:#!/bin/sh#vim:setsw=4ts=4et:help(){cat第3部分:调试最简单的调试命令当然是使用echo命令。
无论您认为哪里出了问题,都可以使用echo打印任何变量值。
这就是为什么绝大多数shell程序员花费80%的时间来调试程序。
shell程序的优点是不需要重新编译,插入echo命令也不需要花太多时间。
shell还具有真正的调试模式。
如果“strangescript”脚本出现错误,可以这样调试:sh-xstrangescript这将运行脚本并显示所有变量的值。
shell还有一种模式,不需要运行脚本,只检查语法。
你可以像这样使用它:sh-nyour_script这将在调试shell程序时返回所有语法错误。
当用户刚写完shell程序时,难免会出现错误。
这时候我们就可以使用提供的跟踪选项了。
在Bsh中,会显示刚刚执行过的命令和参数。
用户可以通过set命令启用-x选项,或者在启动Shell时使用-x选项将Shell设置为跟踪模式。
例如下面的代码ice_tx:if[$#-eq0]thenecho"usage:sumintsintegerlist"exit1fisum=0Until[$#-eq0]dosum='expr$sum+$1'shiftshiftdidecho$sum我们使用跟踪模式:$sh-xice_tx234结果表示:+[3-eq0]+sum=0+[3-eq0]+expr0+2+sum=2+shift+如上所示,在followed模式下,shell在替换命令使用的变量后显示每个执行的命令和参数值。
一些控制词,如if、then、until等。
不显示。