shell脚本for循环_Shell脚本初学者指南2:For循环

shell脚本for循环_Shell脚本初学者指南2:For循环

shell脚本for循环

shell脚本for循环_Shell脚本初学者指南2:For循环

If you want to build up your geek cred, join us for the second installment in our shell scripting series. We have a few corrections, a few improvements to last week’s script, and a guide on looping for the uninitiated.

如果您想建立自己的极客信誉,请加入我们的Shell脚本系列的第二部分。 我们进行了一些更正,对上周的脚本进行了一些改进,以及有关针对未启动者的循环的指南。

重新访问datecp脚本 (The datecp Script Revisited)

In the first installment of our shell scripting guide, we made a script that copied a file to a backup directory after appending the date to the end of the filename.

我们的shell脚本指南第一部分中 ,我们制作了一个脚本,在将日期附加到文件名末尾后,将文件复制到备份目录。

Samuel Dionne-Riel pointed out in the comments that there’s a much better way to handle our variable references.

Samuel Dionne-Riel在评论中指出,有一种更好的方法来处理我们的变量引用。

Arguments are space-separated in the bash shell, it will tokenize when there is a space in the resulted expanded command. In your script, cp $1 $2.$date_formatted will work as intended as long as the expanded variables do not have spaces in them. If you call your script this way: datecp "my old name" "my new name" the expansion will result in this command: cp my new name my old name.the_date which actually has 6 arguments.

参数在bash shell中以空格分隔,当结果扩展命令中有空格时,它将令牌化。 在您的脚本中,只要扩展变量中没有空格, cp $1 $2.$date_formatted就会按预期工作。 如果以这种方式调用脚本: datecp "my old name" "my new name"则扩展将导致以下命令: cp my new name my old name.the_date实际上有6个参数。

To properly address this issue, the last line of the script should be: cp "$1" "$2.$date_formatted"

若要正确解决此问题,脚本的最后一行应为: cp "$1" "$2.$date_formatted"

As you can see, changing our script’s line from:

如您所见,将我们的脚本行从以下位置更改:

cp -iv $1 $2.$date_formatted

cp -iv $ 1 $ 2. $ date_formatted

to:

至:

cp -iv “$1” “$2”.$date_formatted

cp -iv“ $ 1”“ $ 2”。$ date_formatted

will take care of this problem when using the script on files that have spaces in the name. Samuel also makes the point that when copying and pasting code from this site (or the internet in general) be sure to substitute the proper dashes and quotes for the “typographically better” ones that often replace them. We’ll also be doing more to make sure our code is more copy/paste friendly. ;-)

在名称中包含空格的文件上使用脚本时,将解决此问题。 塞缪尔(Samuel)还指出,从此站点(或一般而言,Internet)复制和粘贴代码时,请确保将适当的破折号和引号替换为通常在其上替代的“印刷上更好的”。 我们还将做更多的工作来确保我们的代码对复制/粘贴更加友好。 ;-)

Another commenter, Myles Braithwaite, decided to expand our script so that the date would appear before the file extension. So instead of

另一个评论者Myles Braithwaite决定扩展我们的脚本,以便日期显示在文件扩展名之前。 所以代替

tastyfile.mp3.07_14_11-12.34.56

tastyfile.mp3.07_14_11-12.34.56

we would get this:

我们会得到这个:

tastyfile.07_14_11-12.34.56.mp3

tastyfile.07_14_11-12.34.56.mp3

which ends up being a little more convenient for most users. His code is available at on his GitHub page. Let’s take a look at what he uses to pull apart the filename.

最终对大多数用户来说更加方便。 他的代码可在其GitHub页面找到 。 让我们看一下他用来拆分文件名的内容。

date_formatted=$(date +%Y-%m-%d_%H.%M%S) file_extension=$(echo “$1″|awk -F . ‘{print $NF}’) file_name=$(basename $1 .$file_extension)

date_formatted = $(date +%Y-%m-%d_%H.%M%S)file_extension = $(echo“ $ 1” | awk -F。'{print $ NF}')file_name = $(basename $ 1。 $ file_extension)

cp -iv $1 $file_name-$date_formatted.$file_extension

cp -iv $ 1 $ file_name- $ date_formatted。$ file_extension

I’ve changed the formatting a bit, but you can see that Myles declares his date function in Line 1. In Line 2, however, he uses the “echo” command with the first argument of the script to output the file’s name. He uses the pipe command to take that output and use it as input for the next part. After the pipe, Myles calls on the “awk” command, which is a powerful pattern scanning program. Using the -F flag, he’s telling the command that the next character (after a space) is what will define the “field separator”. In this case, that’s a period.

我对格式进行了一些更改,但是您可以看到Myles在第1行中声明了他的日期函数。但是在第2行中,他使用了带有脚本第一个参数的“ echo”命令来输出文件名。 他使用pipe命令获取该输出,并将其用作下一部分的输入。 在管道之后,Myles调用“ awk”命令,这是一个功能强大的模式扫描程序。 使用-F标志,他告诉命令下一个字符(在空格之后)将定义“字段分隔符”。 在这种情况下,这是一个时期。

Now, awk see a file named “tastyfile.mp3” as being composed of two fields: “tastyfile” and “mp3”. Lastly, he uses

现在,awk看到名为“ tastyfile.mp3”的文件由两个字段组成:“ tastyfile”和“ mp3”。 最后,他使用

‘{print $NF}’

'{print $ NF}'

to display the last field. In case your file has multiple periods – hence making awk see multiple fields – it will only display the last one, which is the file extension.

显示最后一个字段。 如果您的文件有多个句点-因此使awk可以看到多个字段-它只会显示最后一个,即文件扩展名。

In Line 3, he creates a new variable for the file’s name and uses the “basename” command to reference everything in $1 except the file extension. This is done by using basename and giving it $1 as its argument, then adding a space and the file extension. The file extension is automatically added in because of the variable that references Line 2. What this would do is take

在第3行中,他为文件名创建了一个新变量,并使用“ basename”命令引用$ 1中文件扩展名之外的所有内容。 这是通过使用basename并将其赋予$ 1作为其参数,然后添加一个空格和文件扩展名来完成的。 由于引用第2行的变量,文件扩展名被自动添加。

tastyfile.mp3

tastyfile.mp3

and turn it into

然后变成

tastyfile

美味文件

Then in the last line, Myles put together the command that will output everything in order. Note that there is no reference to $2, a second argument for the script. This particular script will copy said file into your current directory instead. Great job Samuel and Myles!

然后在最后一行,Myles组合了将按顺序输出所有内容的命令。 请注意,这里没有引用$ 2,这是脚本的第二个参数。 该特定脚本将代替地将所述文件复制到您的当前目录。 出色的塞缪尔和迈尔斯!

运行脚本和$ PATH (Running Scripts and $PATH)

We also mention in our Basics article that scripts aren’t allowed to be referenced as commands by default. That is, you have to point to the path of the script in order to run it:

我们还在“基础知识”文章中提到,默认情况下不允许将脚本作为命令引用。 也就是说,您必须指向脚本的路径才能运行它:

./script

。/脚本

~/bin/script

〜/ bin /脚本

But, by placing your scripts in ~/bin/, you could just type their names from anywhere to get them to run.

但是,通过将脚本放在〜/ bin /中,您只需在任何地方键入它们的名称即可运行它们。

Commenters spent some time debating how proper this was, as no modern Linux distro creates that directory by default. Furthermore, no one adds it to the $PATH variable by default either, which is what’s required in order for scripts to be run like commands. I was a bit puzzled because after checking my $PATH variable, the commenters were right, but calling scripts still worked for me. I found out why: many modern Linux distros create a special file in the user’s home directory – .profile.

评论者花了一些时间来讨论它的正确性,因为没有现代Linux发行版默认创建该目录。 此外,默认情况下,也没有人将其添加到$ PATH变量中,这是使脚本像命令一样运行所必需的。 我有些困惑,因为在检查了$ PATH变量之后,注释程序是正确的,但是调用脚本仍然对我有用。 我发现了原因:许多现代Linux发行版在用户的主目录-.profile中创建了一个特殊文件。

shell脚本for循环_Shell脚本初学者指南2:For循环

This file is read by bash (unless .bash_profile is present in the user’s home directory) and at the bottom, there’s a section that adds the ~/bin/ folder to the $PATH variable if it exists. So, that mystery is cleared up. For the rest of the series, I’ll continue placing scripts in the ~/bin/ directory because they’re user scripts and should be able to be run by users. And, it seems we don’t really need to mess with the $PATH variable by hand to get things working.

该文件由bash读取(除非用户的主目录中存在.bash_profile),并且在底部,有一个部分将〜/ bin /文件夹添加到$ PATH变量(如果存在)。 因此,这个谜底被清除了。 在本系列的其余部分中,我将继续在〜/ bin /目录中放置脚本,因为它们是用户脚本,应该可以由用户运行。 而且,似乎我们并不需要真正用手弄乱$ PATH变量来使事情正常进行。

用循环重复命令 (Repeating Commands With Loops)

Let’s get to one of the most useful tools in the geek arsenal for dealing with repetitive tasks: loops. Today, we’ll be discussing “for” loops.

让我们进入怪胎库中用于处理重复任务的最有用的工具之一:循环。 今天,我们将讨论“ for”循环。

The basic outline of a for-loop is as follows:

for循环的基本概述如下:

for VARIABLE in LIST; do command1 command2 … commandn done

用于LIST中的VARIABLE; 做command1命令2…命令完成

VARIABLE can be any variable, though most often the lowercase “i” is used by convention. LIST is a list of items; you can specify multiple items (separating them by a space), point to an external text file, or use an asterisk (*) to denote any file in the current directory. The commands listed are indented by convention, so it’s easier to see nesting – putting loops in loops (so you can loop while you loop).

VARIABLE可以是任何变量,尽管通常习惯上使用小写字母“ i”。 LIST是项目列表; 您可以指定多个项目(用空格分隔),指向外部文本文件或使用星号(*)表示当前目录中的任何文件。 列出的命令按约定缩进,因此更容易看到嵌套-将循环放入循环中(这样就可以在循环时循环)。

Because lists use spaces as delimiters – that is, a space signifies a move to the next item in the list – files that have spaces in the name aren’t very friendly. For now, let’s stick to working with files without spaces.Let’s start with a simple script to display the names of files in the current directory. Create a new script in your ~/bin/ folder entitled “loopscript”. If you don’t remember how to do this (including marking it as executable and adding the hash bang hack) refer to our bash scripting basics article.

由于列表使用空格作为分隔符(即,空格表示移至列表中的下一个项目),因此名称中带有空格的文件不是很友好。 现在,让我们继续使用没有空格的文件,让我们从一个简单的脚本开始,以显示当前目录中的文件名。 在〜/ bin /文件夹中创建一个名为“ loopscript”的新脚本。 如果您不记得要怎么做(包括将其标记为可执行文件并添加hash bang hack),请参阅我们的bash脚本基础知识文章

In it, enter the following code:

在其中输入以下代码:

for i in item1 item2 item3 item4 item5 item6; do echo “$i” done

对于项目1,项目2,项目3,项目4,项目5,项目6中的i; 做回声“ $ i”完成

shell脚本for循环_Shell脚本初学者指南2:For循环

When you run the script, you should just get those list items as output.

运行脚本时,应该只获取这些列表项作为输出。

shell脚本for循环_Shell脚本初学者指南2:For循环

Pretty simple, right? Let’s see what happens if we change things up a little bit. Change your script so it says this:

很简单,对吧? 让我们看看如果我们稍微改变一下会发生什么。 更改脚本,使其显示以下内容:

for i in *; do echo “$i” done

因为我在*; 做回声“ $ i”完成

shell脚本for循环_Shell脚本初学者指南2:For循环

When you run this script in a folder, you should get a list of files that it contains as output.

当您在文件夹中运行此脚本时,应该获得包含在其中的文件列表作为输出。

shell脚本for循环_Shell脚本初学者指南2:For循环

Now, let’s change the echo command into something more useful – say, the zip command. Namely, we’ll add files into an archive. And, let’s gets some arguments in the mix!

现在,让我们将echo命令更改为更有用的内容-例如zip命令。 即,我们将文件添加到存档中。 并且,让我们混合一些参数!

for i in [email protected]; do zip archive “$i” done

因为我在$ @; 完成zip存档“ $ i”

shell脚本for循环_Shell脚本初学者指南2:For循环

There’s something new! “[email protected]” is a shortcut for “$1 $2 $3 … $n”. In other words, it’s the full list of all arguments you specified. Now, watch what happens when I run the script with several input files.

有一些新东西! “ $ @”是“ $ 1 $ 2 $ 3…$ n”的快捷方式。 换句话说,它是您指定的所有参数的完整列表。 现在,观察当我用几个输入文件运行脚本时会发生什么。

shell脚本for循环_Shell脚本初学者指南2:For循环

You can see which files are in my folder. I ran the command with six arguments, and each file was added to a zipped archive named “archive.zip”. Easy, right?

您可以看到我的文件夹中有哪些文件。 我运行了带有六个参数的命令,并且每个文件都被添加到名为“ archive.zip”的压缩存档中。 容易吧?

For loops are pretty wonderful. Now you can execute batch functions on lists of files. For example, you can copy all of your script’s arguments into a zipped archive, move the originals to a different folder, and automatically secure copy that zip file to a remote computer. If you set up key files with SSH, you won’t even need to enter your password, and you can even tell the script to delete the zip file after uploading it!

For循环非常棒。 现在,您可以在文件列表上执行批处理功能。 例如,您可以将脚本的所有参数复制到压缩的存档中,将原始文件移动到其他文件夹中,然后自动将该zip文件复制到远程计算机上。 如果您使用SSH设置**文件,则甚至无需输入密码,甚至可以告诉脚本在上传后删除zip文件!



Using for-loops makes it easy to do a bunch of actions for all files in a directory. You can stack a wide variety of commands together and use arguments very easily to create and on-the-fly list, and this is only the tip of the iceberg.

使用for循环可以轻松地对目录中的所有文件执行一系列操作。 您可以将各种命令堆叠在一起,并非常容易地使用参数来创建和即时列出列表,这只是冰山一角。

Bash scripters, do you have any suggestions? Have you made a useful script that uses loops? Want to share you thoughts on the series? Leave some comments and help other scripting newbies out!

Bash脚本编写者,您有什么建议吗? 您是否制作了使用循环的有用脚本? 想分享您对该系列的想法吗? 留下一些评论并帮助其他脚本新手!

翻译自: https://www.howtogeek.com/68184/the-beginners-guide-to-shell-scripting-2-for-loops/

shell脚本for循环