在Linux启动脚本中获取其他脚本

时间:2022-05-26 09:51:11

I came across the following scripts and there is something that I cannot fully understand

我遇到了以下脚本,有些东西我无法完全理解

    #!/bin/sh /etc/rc.common
# Copyright (C) 2006-2011 OpenWrt.org

START=50

start() {
        mkdir -m 0755 -p /var/run/vsftpd
        service_start /usr/sbin/vsftpd
}

stop() {
        service_stop /usr/sbin/vsftpd
}

How is '/etc/rc.common' used here?

如何在这里使用'/etc/rc.common'?

here is the contents of rc.common

这是rc.common的内容

#!/bin/sh
# Copyright (C) 2006-2011 OpenWrt.org

. $IPKG_INSTROOT/lib/functions.sh
. $IPKG_INSTROOT/lib/functions/service.sh

initscript=$1
action=${2:-help}
shift 2

start() {
        return 0
}

stop() {
        return 0
}

reload() {
        return 1
}

restart() {
        trap '' TERM
        stop "$@"
        start "$@"
}

boot() {
        start "$@"
}

shutdown() {
        stop
}

disable() {
        name="$(basename "${initscript}")"
        rm -f "$IPKG_INSTROOT"/etc/rc.d/S??$name
        rm -f "$IPKG_INSTROOT"/etc/rc.d/K??$name
}

enable() {
        name="$(basename "${initscript}")"
        disable
        [ -n "$START" -o -n "$STOP" ] || {
                echo "/etc/init.d/$name does not have a START or STOP value"
                return 1
        }
        [ "$START" ] && ln -s "../init.d/$name" "$IPKG_INSTROOT/etc/rc.d/S${START}${name##S[0-9][0-9]}"
        [ "$STOP"  ] && ln -s "../init.d/$name" "$IPKG_INSTROOT/etc/rc.d/K${STOP}${name##K[0-9][0-9]}"
}

enabled() {
        name="$(basename "${initscript}")"
        [ -x "$IPKG_INSTROOT/etc/rc.d/S${START}${name##S[0-9][0-9]}" ]
}

depends() {
        return 0
}

help() {
        cat <<EOF
Syntax: $initscript [command]

Available commands:
        start   Start the service
        stop    Stop the service
        restart Restart the service
        reload  Reload configuration files (or restart if that fails)
        enable  Enable service autostart
        disable Disable service autostart
$EXTRA_HELP
EOF
}

. "$initscript"

ALL_COMMANDS="start stop reload restart boot shutdown enable disable enabled depends ${EXTRA_COMMANDS}"
list_contains ALL_COMMANDS "$action" || action=help
[ "$action" = "reload" ] && action='eval reload "$@" || restart "$@" && :'
$action "$@"

Hope some of you could shed light on this. Thank you!

希望你们中的一些人能够阐明这一点。谢谢!

PS:Another thing that i don't quite get is how the functions in the scripts are invoked by simply appending the function name to the full path of the startup scripts. for example, '/etc/init.d/vsftpd test' will execute a function named 'test' in either /etc/init.d/vsftpd or /etc/rc.common.But if 'test' function is defined both in the startup script and /etc/rc.common, the function in the former will be run while the one in rc.common will not.

PS:我不太了解的另一件事是如何通过简单地将函数名称附加到启动脚本的完整路径来调用脚本中的函数。例如,'/ etc / init.d / vsftpd test'将在/etc/init.d/vsftpd或/etc/rc.common.But中执行名为'test'的函数,如果'test'函数在启动脚本和/etc/rc.common,前者中的函数将运行,而rc.common中的函数则不会。

Also, why is not

另外,为什么不呢

'[ "$action" = "reload" ] && action='eval reload "$@" || restart "$@" && :'

simply written as

简单地写成

'[ "$action" = "reload" ] && action='eval reload "$@" || restart "$@"'

Thank you!

谢谢!

1 个解决方案

#1


1  

From execve(2) on a fairly current Linux system:

来自execve(2)的一个相当新的Linux系统:

Interpreter scripts

解释器脚本

An interpreter script is a text file that has execute permission enabled and whose first line is of the form:

解释器脚本是一个启用了执行权限且第一行具有以下形式的文本文件:

#! interpreter [optional-arg]

The interpreter must be a valid pathname for an executable which is not itself a script. If the filename argument of execve() specifies an interpreter script, then interpreter will be invoked with the following arguments:

解释器必须是可执行文件的有效路径名,而该可执行文件本身不是脚本。如果execve()的filename参数指定了解释器脚本,则将使用以下参数调用解释器:

interpreter [optional-arg] filename arg...

where arg... is the series of words pointed to by the argv argument of execve().

其中arg ...是execve()的argv参数指向的一系列单词。

For portable use, optional-arg should either be absent, or be specified as a single word (i.e., it should not contain white space); [...]

对于便携式使用,可选的arg应该不存在,或者指定为单个单词(即,它不应包含空格); [...]

I have not seen many scripts in the wild using the #!/bin/sh filename idiom. I find its use confusing.

我没有在#!/ bin / sh文件名中找到很多脚本。我发现它的使用令人困惑。

Perhaps a simple test will illustrate. These files should be present in /tmp/test, which matters in this case, given the details of the interpreter line in test_interpreter.sh.

也许一个简单的测试将说明。考虑到test_interpreter.sh中解释器行的详细信息,这些文件应该出现在/ tmp / test中,这在本例中很重要。

The script named in the "#!" line (rc_interpreter_line) arranges to run commands in the originally invoked script, which I do via the sourcing_script variable and shift command. The code you quote in the question does a rather more complicated version of this chaining. Without this kind of chaining, all that runs is the file named in the interpreter line.

脚本命名为“#!” line(rc_interpreter_line)安排在最初调用的脚本中运行命令,我通过sourcing_script变量和shift命令执行此操作。你在问题中引用的代码是一个相当复杂的链接版本。没有这种链接,所有运行的都是在解释器行中命名的文件。

Contents of rc_interpreter_line

rc_interpreter_line的内容

echo '===='
echo $0 "$@"

TESTVAR=set

sourcing_script=$1
shift

. "$sourcing_script" "$@"

echo '===='

Contents of test_interpreter.sh

test_interpreter.sh的内容

#!/bin/sh /tmp/test/rc_interpreter_line

echo '-----'
echo "My file name is test_interpreter.sh, but \$0 is $0"

echo Command line: $0 "$@"

echo "TESTVAR is '$TESTVAR'"
echo '-----'

exit 0

Permissions:

权限:

sh-4.2$ ls -l
total 8
-rw-r--r-- 1 dev dev 104 Aug 24 13:36 rc_interpreter_line
-rwxr-xr-x 1 dev dev 191 Aug 24 13:36 test_interpreter.sh

Sample runs. Run test_interpreter.sh directly first.

样品运行。首先直接运行test_interpreter.sh。

sh-4.2$ ./test_interpreter.sh -opt arg1 arg2
====
/tmp/test/rc_interpreter_line ./test_interpreter.sh -opt arg1 arg2
-----
My file name is test_interpreter.sh, but $0 is /tmp/test/rc_interpreter_line
Command line: /tmp/test/rc_interpreter_line -opt arg1 arg2
TESTVAR is 'set'
-----

The second invokes the shell more plainly. No execve(2) behavior firing, so this run of the shell simply runs the commands in test_interpreter.sh, treating that first line as a comment.

第二个更明确地调用shell。没有execve(2)行为触发,所以shell的这个运行只是运行test_interpreter.sh中的命令,将第一行视为注释。

sh-4.2$ sh test_interpreter.sh -opt arg1 arg2
-----
My file name is test_interpreter.sh, but $0 is test_interpreter.sh
Command line: test_interpreter.sh -opt arg1 arg2
TESTVAR is ''
-----

But my personal preference is to avoid the idiom entirely. It's far clearer to me to simply use commands early in scripts like:

但我个人的偏好是完全避免使用成语。简单地在脚本中使用命令就可以了得更清楚:

. /etc/rc.common

...rather than rely on "interesting" '#!' lines, and in doing so create different behavior when using ./my_script and sh my_script

...而不是依赖“有趣”的'#!'在使用./my_script和sh my_script时,这样做会产生不同的行为

#1


1  

From execve(2) on a fairly current Linux system:

来自execve(2)的一个相当新的Linux系统:

Interpreter scripts

解释器脚本

An interpreter script is a text file that has execute permission enabled and whose first line is of the form:

解释器脚本是一个启用了执行权限且第一行具有以下形式的文本文件:

#! interpreter [optional-arg]

The interpreter must be a valid pathname for an executable which is not itself a script. If the filename argument of execve() specifies an interpreter script, then interpreter will be invoked with the following arguments:

解释器必须是可执行文件的有效路径名,而该可执行文件本身不是脚本。如果execve()的filename参数指定了解释器脚本,则将使用以下参数调用解释器:

interpreter [optional-arg] filename arg...

where arg... is the series of words pointed to by the argv argument of execve().

其中arg ...是execve()的argv参数指向的一系列单词。

For portable use, optional-arg should either be absent, or be specified as a single word (i.e., it should not contain white space); [...]

对于便携式使用,可选的arg应该不存在,或者指定为单个单词(即,它不应包含空格); [...]

I have not seen many scripts in the wild using the #!/bin/sh filename idiom. I find its use confusing.

我没有在#!/ bin / sh文件名中找到很多脚本。我发现它的使用令人困惑。

Perhaps a simple test will illustrate. These files should be present in /tmp/test, which matters in this case, given the details of the interpreter line in test_interpreter.sh.

也许一个简单的测试将说明。考虑到test_interpreter.sh中解释器行的详细信息,这些文件应该出现在/ tmp / test中,这在本例中很重要。

The script named in the "#!" line (rc_interpreter_line) arranges to run commands in the originally invoked script, which I do via the sourcing_script variable and shift command. The code you quote in the question does a rather more complicated version of this chaining. Without this kind of chaining, all that runs is the file named in the interpreter line.

脚本命名为“#!” line(rc_interpreter_line)安排在最初调用的脚本中运行命令,我通过sourcing_script变量和shift命令执行此操作。你在问题中引用的代码是一个相当复杂的链接版本。没有这种链接,所有运行的都是在解释器行中命名的文件。

Contents of rc_interpreter_line

rc_interpreter_line的内容

echo '===='
echo $0 "$@"

TESTVAR=set

sourcing_script=$1
shift

. "$sourcing_script" "$@"

echo '===='

Contents of test_interpreter.sh

test_interpreter.sh的内容

#!/bin/sh /tmp/test/rc_interpreter_line

echo '-----'
echo "My file name is test_interpreter.sh, but \$0 is $0"

echo Command line: $0 "$@"

echo "TESTVAR is '$TESTVAR'"
echo '-----'

exit 0

Permissions:

权限:

sh-4.2$ ls -l
total 8
-rw-r--r-- 1 dev dev 104 Aug 24 13:36 rc_interpreter_line
-rwxr-xr-x 1 dev dev 191 Aug 24 13:36 test_interpreter.sh

Sample runs. Run test_interpreter.sh directly first.

样品运行。首先直接运行test_interpreter.sh。

sh-4.2$ ./test_interpreter.sh -opt arg1 arg2
====
/tmp/test/rc_interpreter_line ./test_interpreter.sh -opt arg1 arg2
-----
My file name is test_interpreter.sh, but $0 is /tmp/test/rc_interpreter_line
Command line: /tmp/test/rc_interpreter_line -opt arg1 arg2
TESTVAR is 'set'
-----

The second invokes the shell more plainly. No execve(2) behavior firing, so this run of the shell simply runs the commands in test_interpreter.sh, treating that first line as a comment.

第二个更明确地调用shell。没有execve(2)行为触发,所以shell的这个运行只是运行test_interpreter.sh中的命令,将第一行视为注释。

sh-4.2$ sh test_interpreter.sh -opt arg1 arg2
-----
My file name is test_interpreter.sh, but $0 is test_interpreter.sh
Command line: test_interpreter.sh -opt arg1 arg2
TESTVAR is ''
-----

But my personal preference is to avoid the idiom entirely. It's far clearer to me to simply use commands early in scripts like:

但我个人的偏好是完全避免使用成语。简单地在脚本中使用命令就可以了得更清楚:

. /etc/rc.common

...rather than rely on "interesting" '#!' lines, and in doing so create different behavior when using ./my_script and sh my_script

...而不是依赖“有趣”的'#!'在使用./my_script和sh my_script时,这样做会产生不同的行为