【问题标题】:Use of CD in Bash For Loop - only getting relative path在 Bash For Loop 中使用 CD - 仅获取相对路径
【发布时间】:2020-04-28 14:25:08
【问题描述】:

我有一个用于组织目录中文件的小脚本,现在我正尝试在一个或多个文件夹中运行它。 MasterDir/dir1、MasterDir/dir2等

MasterDir 上运行以下代码会导致错误,因为$dir 只是一个相对路径,但在这种情况下我不知道如何获取$dir 的完整路径

for dir in */; do
    echo $dir
    cd $dir
    cwd="$PWD"
    mkdir -p "VSI"
    mv -v *.vsi "$cwd/VSI"
    mv -v _*_ "$cwd/VSI"
done

【问题讨论】:

  • 查看this
  • absdir="$(readlink -f "$dir")"; pushd "$absdir" &>/dev/null; # cd through mv; popd &>/dev/null

标签: bash


【解决方案1】:

我建议使用括号在子外壳中运行循环体:

for dir in */; do
    (
        echo $dir
        cd $dir
        cwd="$PWD"
        mkdir -p "VSI"
        mv -v *.vsi "$cwd/VSI"
        mv -v _*_ "$cwd/VSI"
    )
done

由于它在子 shell 中运行,cd 命令不会影响执行脚本的父 shell。

【讨论】:

    【解决方案2】:

    您遇到的问题是,在您第一次cd "$dir" 之后,您是下面的一个目录,您在其中生成了带有for dir in */ 的目录列表。因此,下次您调用 cd "$dir" 时它会失败,因为您仍然在您 cd 进入的第一个子目录中,而列表中的下一个 "$dir" 位于上一层。

    有几种方法可以处理这个问题。一种简单的方法是使用pushd而不是cd切换到目录,这样你就可以popd回到原来的目录。 (虽然在这种情况下,您可以简单地添加 cd .. 以更改回父目录,因为您只有一级深度)

    使用pushd/popd 你可以这样做:

    for dir in */; do
        echo $dir
        pushd "$dir" &>/dev/null || {
            printf "error: failed to change to %s\n" "$dir" >&2
            continue
        }
        cwd="$PWD"
        mkdir -p "VSI" || {
            printf "error: failed to create %s\n" "$cwd/VSI" >&2
            continue
        }
        mv -v *.vsi "$cwd/VSI"
        mv -v _*_ "$cwd/VSI"
        popd &>/dev/null || {
            printf "error: failed to return to parent dir\n" >&2
            break
        }
    done
    

    (注意:|| 测试验证pushd, mkdir, popd 的返回,导致循环继续到下一个目录,或者如果您无法返回到原始目录,则中断循环。还要注意&>/dev/null 只是抑制pushd/popd 的正常输出,输出重定向到>&2 将输出发送到stderr 而不是stdout

    正如评论中提到的,您始终可以使用readlink -f "$dir" 生成"$dir" 的绝对路径——尽管这里并不真正需要它。

    【讨论】:

      【解决方案3】:

      这是我倾向于避免在 shell 脚本中使用cd 的原因之一——当您使用cd 时,所有相对文件路径的含义都会改变,如果您对此不太小心,您可能会遇到麻烦。另一个是cd 可能会失败(例如,由于权限错误),在这种情况下,您最好有一个错误检查和处理程序,否则会发生更奇怪的事情。

      IMO 仅使用显式路径来引用其他目录中的文件要安全得多。也就是说,使用 `mkdir -p "somedir/VSI" 代替 cd somedir; mkdir -p "VSI"。这是使用这种方法重写你的循环:

      for dir in */; do
          echo $dir
          mkdir -p "${dir}/VSI"
          mv -v "${dir}"/*.vsi "${dir}/VSI"
          mv -v "${dir}"/_*_ "${dir}/VSI"
      done
      

      注意:$dir 的值将以斜杠结尾,因此使用例如${dir}/VSI 将给出类似“somedir//VSI”的结果。多余的斜线是多余的,但不应该造成麻烦;为了清楚起见,我更喜欢使用它。如果它很烦人(例如在mv -v 的输出中),您可以省略多余的斜线。

      【讨论】:

        猜你喜欢
        • 2012-01-02
        • 2022-06-10
        • 1970-01-01
        • 2014-01-26
        • 2019-02-19
        • 2023-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多