为什么此递归函数在Bash中不起作用?

时间:2019-05-03 15:47:07

标签: bash

我已经在Bash中编写了一个递归函数,以从各种目录中收集Python源文件,这些目录通过requirements.in文件链接在一起。我能够找到一种解决方法来使我的Bash函数正常工作,但是由于我无法解释的原因,原始代码无法正常工作。我将提供既定解决方案(不起作用)及其解决方法的MCVE。但是首先,我必须解释一下我如何进行文件中的requires.link的链接。

如果您使用过Python,那么您一定对Requirements.txt文件很熟悉。不久之前,我了解到,可以通过将诸如以下内容这样的行与所有其他需求保持一致来将不同的requirements.txt文件链接在一起:

-r path/to/other/requirements.txt

有一个名为pip-compile的第三方工具,实际上在文件中使用了类似的requirements.。对于该问题的所有意图和目的,都应将它们视为与requirements.txt文件相同;与股票pip相比,pip-compile具有更好的依赖管理更好的好处。但是这些文件同样可以包含要安装的pip软件包的两个定义,以及指向其他需求的相对链接。

我的Bash功能旨在执行以下操作:

  1. 给出一个起始目录,找到所有*.py个文件
  2. 如果有requirements.in文件,请对其进行扫描以查看是否还有其他链接文件
  3. 如果是,请递归到该目录并重复(查找*.py文件和其他链接的文件)

现在,这是我正在使用的(简化的)文件结构:

.
├── include1
│   ├── __init__.py
│   └── requirements.in
├── include2
│   ├── __init__.py
│   └── requirements.in
└── start
    ├── __init__.py
    ├── main.py
    └── requirements.in

为了这个示例,这是文件中这三个要求的文件内容:

include1 / requirements.in

hvac
-r include2/requirements.in

包括2 /要求。

requests

开始/要求。

click
python-dotenv
-r include1/requirements.in

因此,鉴于文件结构和内容,我的函数的期望输出如下:

start/__init__.py
start/main.py
include1/__init__.py
include2/__init__.py

到目前为止和我在一起吗?因此,这是我编写Bash函数以实现此目的的第一步:

find-sr​​cs.sh :(不起作用-应该起作用)

#!/bin/bash
set -eo pipefail

START_DIR="$1"
SRCS=""

find_srcs() {
  local DIR="$1"
  local IN_FILE=$(ls "$DIR" | grep -s -E '^.*\.in$' || echo "")
  if [ -n "$IN_FILE" ]; then
    THIS_SRCS=$(find "$DIR" -name '*.py' | paste -sd ' ')
    SRCS="$SRCS $THIS_SRCS"
    local SUB_REQS=$(grep "requirements.in" "$DIR/$IN_FILE" || echo "")
    if [ -n "$SUB_REQS" ]; then
      echo "$SUB_REQS" | while read -r SUB_REQ; do
        SUB_REQ=$(echo "$SUB_REQ" | sed -r 's/\-r (.*)\/requirements\.in/\1/')
        find_srcs "$SUB_REQ"
      done
    fi
  fi
}

find_srcs "$START_DIR"
# echo the concatenated values here, once at the end
echo "$SRCS" | xargs | tr " " "\n"

因此,当使用以下命令从我的目录结构的根目录(如上)调用时:

./find-srcs.sh start

...我希望看到上面发布的预期输出。相反,我只能看到以下输出:

start/__init__.py
start/main.py

现在这是我的解决方法。仔细观察:此替代方法实际上与我刚刚发布的功能完全相同。但是,不是像我在SRCS变量中那样收集源,然后在末尾输出一次,而是在每次调用该函数时输出THIS_SRCS的值:

find-sr​​cs.sh :(解决方法)

#!/bin/bash
set -eo pipefail

START_DIR="$1"

find_srcs() {
  local DIR="$1"
  local IN_FILE=$(ls "$DIR" | grep -s -E '^.*\.in$' || echo "")
  if [ -n "$IN_FILE" ]; then
    THIS_SRCS=$(find "$DIR" -name '*.py')
    # echo the values - as they are collected - here instead
    echo "$THIS_SRCS"
    local SUB_REQS=$(grep "requirements.in" "$DIR/$IN_FILE" || echo "")
    if [ -n "$SUB_REQS" ]; then
      echo "$SUB_REQS" | while read -r SUB_REQ; do
        SUB_REQ=$(echo "$SUB_REQ" | sed -r 's/\-r (.*)\/requirements\.in/\1/')
        find_srcs "$SUB_REQ"
      done
    fi
  fi
}

find_srcs "$START_DIR"

有了这种解决方法,当我调用./find-srcs.sh start时,它确实会产生所需的输出。 它有效。这告诉了我一些有关原始功能的信息。这意味着在我的原始函数中,确实确实正确地调用了递归循环。这意味着它确实在每次循环调用时正确分配了THIS_SRCS的值。但是由于某种原因,只有第一次调用被保存到SRCS中。嵌套调用中的值实际上已被丢弃。

在我看来,该函数的第一个版本存在的问题与变量范围有关。但是我在Bash中创建了其他甚至更简单的递归函数,这些函数更新了不受此情况影响的变量的值。为什么我的原始函数中的SRCS的值在第一次调用后仍不保留其值?

0 个答案:

没有答案