Shell 脚本中是否有类似“包含防护”的机制?在 C++ 中?

发布于 2024-12-06 04:05:21 字数 113 浏览 1 评论 0原文

让我们看一个例子:在我的 main.sh 中,我想获取 a.sh 和 b.sh 的源码。然而,a.sh 可能已经采购了 b.sh。这样就会导致b.sh中的代码被执行两次。 C++ 中是否有类似“包含防护”的机制?

let's see an example: in my main.sh, I'd like to source a.sh and b.sh. a.sh, however, might have already sourced b.sh. Thus it will cause the codes in b.sh executed twice. Is there any mechanism alike "include guard" in C++?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

沉鱼一梦 2024-12-13 04:05:21

如果您正在采购脚本,通常会使用它们来定义函数和/或变量。

这意味着您可以通过测试脚本定义的(其中之一)函数或变量来测试脚本是否已被获取。

例如(在b.sh中):

if [ -z "$B_SH_INCLUDED" ]
then
    B_SH_INCLUDED=yes
    ...rest of original contents of b.sh
fi

据我所知,没有其他方法可以做到这一点。特别是,您不能提前退出或返回,因为这会影响 shell 获取文件。您不必使用专门用于该文件的名称;您可以使用文件始终定义的名称。

If you're sourcing scripts, you are usually using them to define functions and/or variables.

That means you can test whether the script has been sourced before by testing for (one of) the functions or variables it defines.

For example (in b.sh):

if [ -z "$B_SH_INCLUDED" ]
then
    B_SH_INCLUDED=yes
    ...rest of original contents of b.sh
fi

There is no other way to do it that I know of. In particular, you can't do early exits or returns because that will affect the shell sourcing the file. You don't have to use a name that is solely for the file; you could use a name that the file always has defined.

画骨成沙 2024-12-13 04:05:21

在 bash 中,早期返回不会影响源文件,它会像当前文件是一个函数一样返回源文件。我更喜欢这种方法,因为它避免了将整个内容包装在 if...fi 中。

if [ -n "$_for_example" ]; then return; fi
_for_example=`date`

In bash, an early return does not affect the sourcing file, it returns to it as if the current file were a function. I prefer this method because it avoids wrapping the entire content in if...fi.

if [ -n "$_for_example" ]; then return; fi
_for_example=`date`
情感失落者 2024-12-13 04:05:21
TL;DR:

Bash 有一个源防护机制,可让您决定执行或获取源后要做什么。

更长的版本:

在使用 Bash 采购的这些年中,我发现一种不同的方法效果非常好,我将在下面讨论。

对我来说,问题与原始发帖人的问题类似:

  1. 采购其他脚本会导致双重脚本执行
  2. ,脚本使用 BATS 等单元测试框架的可测试性较差。

我的解决方案的主要思想是以一种可以安全地编写脚本的方式编写脚本。多次来源。主要部分是功能的提取(与大型脚本相比,它不会变得非常可测试)。

因此,只定义了函数和全局变量,其他脚本可以随意获取。

例如,考虑以下三个 bash 脚本:

ma​​in.sh

#!/bin/env bash

source script2.sh
source script3.sh

GLOBAL_VAR=value

function_1() {
  echo "do something"
  function_2 "completely different"
}

run_main() {
  echo "starting..."
  function_1
}

# Enter: the source guard
# make the script only run when executed, not when sourced)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
  run_main "$@"
fi

script2.sh

#!/bin/env bash

source script3.sh

ALSO_A_GLOBAL_VAR=value2

function_2() {
  echo "do something ${1}"
}

# this file can be sourced or be executed if called directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
  function_2 "$@"
fi

script3.sh

#!/bin/env bash

export SUPER_USEFUL_VAR=/tmp/path

function_3() {
  echo "hello again"
}

# no source guard here: this script defines only the variable and function if called but does not executes them because no code inside refers to the function.

请注意 script3.sh< /code> 来源两次。但由于仅(重新)定义了函数和变量,因此在源代码期间不会执行任何功能代码。

正如人们所期望的那样,执行从运行 main.sh 开始。

当涉及到依赖循环时可能存在一个缺点(通常是一个坏主意):我不知道如果文件(直接或间接)相互引用,Bash 会如何反应。

TL;DR:

Bash has a source guard mechanism which lets you decide what to do if executed or sourced.

Longer version:

Over the years working with Bash sourcing I found that a different approach worked excellently which I will discuss below.

The problem for me was similar to the one of the original poster:

  1. sourcing other scripts led to double script execution
  2. additionally, scripts are less testable with unit test frameworks like BATS

The main idea of my solution is to write scripts in a way that can safely sourced multiple times. A major part plays the extraction of functionality (compared to have a large script which would not render very testable).

So, only functions and global variables are defined, other scripts can be sourced at will.

As an example, consider the following three bash scripts:

main.sh

#!/bin/env bash

source script2.sh
source script3.sh

GLOBAL_VAR=value

function_1() {
  echo "do something"
  function_2 "completely different"
}

run_main() {
  echo "starting..."
  function_1
}

# Enter: the source guard
# make the script only run when executed, not when sourced)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
  run_main "$@"
fi

script2.sh

#!/bin/env bash

source script3.sh

ALSO_A_GLOBAL_VAR=value2

function_2() {
  echo "do something ${1}"
}

# this file can be sourced or be executed if called directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
  function_2 "$@"
fi

script3.sh

#!/bin/env bash

export SUPER_USEFUL_VAR=/tmp/path

function_3() {
  echo "hello again"
}

# no source guard here: this script defines only the variable and function if called but does not executes them because no code inside refers to the function.

Note that script3.sh is sourced twice. But since only functions and variables are (re-)defined, no functional code is executed during the sourcing.

The execution starts with with running main.sh as one would expect.

There might be a drawback when it comes to dependency cycles (in general a bad idea): I have no idea how Bash reacts if files source (directly or indirectly) each other.

梦过后 2024-12-13 04:05:21

使用

set +o nounset # same as set -u

就我个人而言,我通常在大多数脚本上

#!/usr/bin/env bash

set +u
if [ -n "$PRINTF_SCRIPT_USAGE_SH" ] ; then
    set -u
    return
else
    set -u
    readonly PRINTF_SCRIPT_USAGE_SH=1
fi

,因此我总是将其关闭然后重新打开。如果你不喜欢名词集,你可以这样做

[[ -n "$PRINTF_SCRIPT_USAGE_SH" ]] && return || readonly PRINTF_SCRIPT_USAGE_SH=1

Personally I usually use

set +o nounset # same as set -u

on most of my scripts, therefore I always turn it off and back on.

#!/usr/bin/env bash

set +u
if [ -n "$PRINTF_SCRIPT_USAGE_SH" ] ; then
    set -u
    return
else
    set -u
    readonly PRINTF_SCRIPT_USAGE_SH=1
fi

If you do not prefer nounset, you can do this

[[ -n "$PRINTF_SCRIPT_USAGE_SH" ]] && return || readonly PRINTF_SCRIPT_USAGE_SH=1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文