简体   繁体   English

编写Shell脚本的Shell脚本

[英]Shell script that writes a shell script

Two questions: how can I write a shell variable from this script into its child script? 两个问题:如何从此脚本将shell变量写入其子脚本?

Are there any easier ways to do this? 有没有更简单的方法可以做到这一点?

If you can't follow what I'm doing, I'm: 如果您听不懂我在做什么,那我就是:

1) starting with a list of directories whose names will be stored as values taken by $i 1)从目录列表开始,其名称将存储为$ i所取值

2) cd'ing to every value of $i and ls'ing its contents 2)对$ i的每个值进行cd'处理并使其内容

3) echoing its contents into a new script with the name of the directory via cat 3)通过cat将目录内容回显到新脚本中

4) using echo and cat to write a new script that contains the ls'd values of $i and sends them all to a blogging email address called $i@tumblr.com 4)使用echo和cat编写一个包含$ i的ls'd值的新脚本,并将它们全部发送到名为$i@tumblr.com的博客电子邮件地址

#/bin/sh
read -d '' commands <<EOF

#list of directories goes here
dir1
dir2
dir3
etc...    

EOF

for i in $commands
do

cd $SPECIALPATH/$i
echo ("#/bin/sh \n read -d '' directives <<EOF \n") | cat >> $i.sh
ls | cat >> $i.sh
echo ("EOF \n for q in $directives \n do \n uuencode $q $q | sendmail $i \n done \n") | cat >> $i.sh
# NB -- I am asking the script to write the shell variable $i into the new
# script, called $i.sh, as the email address specified, in the middle of an
# echo statement... I am well aware that it doesn't work as is
chmod +x $i.sh
./$i.sh    

done

You are abusing felines a lot - you should simply redirect, rather than pipe to cat which appends. 您经常滥用猫科动物-您应该简单地重定向,而不是通过管道将其添加到cat身上。

You can avoid the intermediary $i.sh file by bundling all the output that goes to the file with a single I/O redirection that pipes direct into a shell - no need for the intermediate file to clean up (you didn't show that happening) or the chmod operation. 您可以通过将直接输入到外壳程序的单个I / O重定向捆绑到文件的所有输出,从而避免使用中间$i.sh文件-无需清理中间文件(您没有显示发生)或chmod操作。

I would have done this using braces: 我会用花括号来做到这一点:

{
echo "..."
ls
echo "..."
} | sh

However, when I looked at the script in that form, I realized that wasn't necessary. 但是,当我以这种形式查看脚本时,我意识到这不是必需的。 I've left the initial part of your script unchanged, but the loop is vastly simpler like this: 我保留了脚本的初始部分不变,但是循环非常简单,如下所示:

#/bin/sh
read -d '' commands <<EOF

#list of directories goes here
dir1
dir2
dir3
etc...    

EOF

for i in $commands
do
    (
    cd $SPECIALPATH/$i
    ls |
    while read q
    do uuencode $q $q | sendmail $i
    done
    )
done

I'm assuming the sendmail command works - it isn't the way I'd try sending email. 我假设sendmail命令有效-这不是我尝试发送电子邮件的方式。 I'd probably use mailx or something similar, and I'd avoid using uuencode too (I'd use a base-64 encoding, left to my own devices): 我可能会使用mailx或类似的东西,并且也避免使用uuencode (我将使用base-64编码,留给自己的设备使用):

    do uuencode $q $q | mailx -s "File $q" $i@tumblr.com

The script also uses parentheses around the cd command. 该脚本还在cd命令周围使用括号。 It means that the cd command and what follows is run in a sub-shell, so the parent script does not change directory. 这意味着cd命令及其后的命令在子外壳中运行,因此父脚本不会更改目录。 In this case, with an absolute pathname for $SPECIALDIR, it would not matter much. 在这种情况下,使用$ SPECIALDIR的绝对路径名没有太大关系。 But as a general rule, it often makes life easier if you isolate directory changes like that. 但是通常,如果这样隔离目录更改,通常会使工作变得更轻松。

I'd probably simplify it still further for general reuse (though I'd need to add something to ensure that SPECIALPATH is set appropriately): 我可能会进一步简化它以进行常规重用(尽管我需要添加一些内容以确保适当设置SPECIALPATH):

#/bin/sh

for i in "$@"
do
    (
    cd $SPECIALPATH/$i
    ls |
    while read q
    do uuencode $q $q | sendmail $i
    done
    )
done

I can then invoke it with: 然后可以使用以下命令调用它:

script-name $(<list-of-dirs)

That means that without editing the script, it can be reused for any list of directories. 这意味着无需编辑脚本,就可以将其重新用于任何目录列表。


Intermediate step 1: 中间步骤1:

for i in $commands
do
    (
    cd $SPECIALPATH/$i
    {
    echo "read -d '' directives <<EOF"
    ls 
    echo "EOF"
    echo "for q in $directives"
    echo "do"
    echo "    uuencode $q $q | sendmail $i"
    echo "done"
    } |
    sh
    )
done

Personally, I find it easier to read the generated script if the code that generates makes the generated script clear - using multiple echo commands. 就个人而言,我发现如果生成的代码使生成的脚本清晰可见(使用多个echo命令),则更容易阅读生成的脚本。 This includes indenting the code. 这包括缩进代码。

Intermediate Step 2: 中间步骤2:

for i in $commands
do
    (
    cd $SPECIALPATH/$i
    {
    ls |
    echo "while read q"
    echo "do"
    echo "    uuencode $q $q | sendmail $i"
    echo "done"
    } |
    sh
    )
done

I don't need to read the data into a variable in order to step through each item in the list once - simply read each line in turn. 我不需要将数据读入变量即可一次浏览列表中的每个项目-只需依次读取每一行。 The while read mechanism is often useful for splitting up a line into multiple variables too: while read var1 var2 var3 junk will read the first field into $var1 , the second into $var2 , the third into $var3 , and if there's anything left over, it goes into $junk . while read机制通常对于将行也拆分为多个变量很有用: while read var1 var2 var3 junk将读取第一个字段为$var1 ,第二个字段为$var2 ,第三个字段为$var3 ,如果还有剩余的内容,则变成$junk If you've generated the data accurately, there won't be any junk; 如果您准确地生成了数据,就不会有垃圾。 but sometimes you have to deal with other people's data. 但有时您必须处理其他人的数据。

If the generated script is meant to be temporary, I would not use files. 如果生成的脚本是临时脚本,则不会使用文件。 Besides, chmoding them to executable sounds unsafe. 此外,将它们更改为可执行文件听起来不安全。 When I needed to parallel my scripting, I used a bash script to form a set of commands (in an array, split the array in two, then implode the array) to a single \\n -separated string and then pass that to a new bash instance. 当我需要并行执行脚本时,我使用了bash脚本来形成一组命令(在一个数组中,将该数组拆分为两个,然后分解该数组)为单个\\n分隔的字符串,然后将其传递给新的字符串。 bash实例。

Basically, in bash: 基本上,在bash中:

for orig in "$@"
do
    commands="$commands echo \"echoeing stuff here for arguments $orig\" \n"
done 

echo -e $commands |bash 

And a small tip: if the script doesn't need supervising, throw in a & after the piped bash to make your first script quit and do the rest of the work forked background. 还有一个小技巧:如果脚本不需要监督,请在竖线bash之后添加& ,以使您的第一个脚本退出,并完成分支背景的其余工作。

If you export a variable 如果导出变量

export VAR1=FOO

it'll be present in any child processes. 它会出现在任何子进程中。

If you take a look at the init scripts, /etc/init..d/* you'll notice that many source another file full of "external" definitions. 如果查看init脚本/etc/init..d/*,您会注意到许多脚本都在另一个源文件中充满了“外部”定义。 You could set up a file like that and have your child script source these files. 您可以设置一个类似的文件,并让您的子脚本来获取这些文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM