首页 > 解决方案 > 带有绝对路径和控制错误的 Shell 脚本

问题描述

我正在做这个小脚本,其中第一个参数必须是现有目录的路径,第二个参数必须是其他任何东西。必须重命名第一个参数中指示的路径中的每个对象,以便新名称是作为前缀添加到作为第二个参数传递的字符串的原始名称。例如,对于字符串“hello”,对象 OBJECT1 被重命名为 hello.OBJECT1 等等

此外,如果已存在具有新名称的对象,则标准错误输出会显示一条消息,并且不会继续执行下一个对象的操作。

我做了以下事情:

#! /bin/bash

if [ "$#" != 2 ]; then
        exit 1
else
        echo "$2"
        if [ -d "$1" ]; then
                echo "directory"
            for i in $(ls "$1")
                do
                for j in $(ls "$1")
                   do
                      echo "$i"
                      if [ "$j" = "$2"."$i" ]; then
                         exit 1
                      else
                         mv -v "$i" "$2"."$i"
                         echo "$2"."$i"
                      fi
                done
            done

        else
           echo "no"
        fi
fi

如果我从另一个文件而不是我想要执行的文件运行脚本,我会遇到问题,例如,如果我在 /home/pp 中并且我希望在 /home/pp/rr 中进行更改,因为那是它在当前所做的唯一方法。

我试图更改 ls 以使用 ls -R | 捕捉整个路线 sed "s;^; pwd;" 但这条路线让我很受不了。

使用 find 你不能因为它把我放在路径前面并且不会离开文件

然后是另一个问题,为了验证将要创建新的对象不在内部,当使用两个 for 执行此操作时,我得到所有文件的 bash 错误,而不仅仅是巧合

我从这个脚本开始,所以它必须是一个非常简单的解决方案

标签: bashshell

解决方案


您的问题的一个明显答案是cd "$2在脚本中添加 a 以使其工作。但是,此脚本中有一些改进的机会。

#! /bin/bash

if [ "$#" != 2 ]; then

例如,您可能会在此处输入错误消息,echo "Usage: $0 dir prefix"或者甚至是更详细的帮助文本。

    exit 1
else
    echo $2

请引用,如echo "$2".

    if [ -d $1 ]; then

在这里,引号很重要。假设您的目录名称中有一个空格;那么这个 if 会失败bash: [: a: binary operator expected。因此,在 $1 周围加上引号:if [ -d "$1" ]; then

        echo "directory"

这是您可以插入cd "$1".

        for i in $(ls $1)
            do

解析的输出几乎总是一个坏主意ls。同样,如果文件名中有空格,则此 for 循环将失败。一个可能的改进是for i in "$1"/* ; do

            for j in $(ls $1)
               do
                  echo $i
                  if [ $j = $2.$i ]; then
                     exit 1
                  else

这部分的逻辑似乎是:如果存在带有前缀的文件,则退出而不是覆盖。说明脚本失败的原因总是一个好主意。echo前一个会有exit 1帮助。

问题是你为什么使用第二个循环?一个简单的if [ -f "$2.$i ] ; then会做同样的事情,但没有第二个循环。因此它会更快。

                     mv -v $i $2.$i
                     echo $2.$i

再次:使用引号!

                  fi
            done
        done

    else
       echo "no"
    fi
fi

因此,有了所有的评论,您应该能够改进您的脚本。正如 Tripleee 在他的评论中所说,运行 shellcheck 会为您提供上面的大部分评论。但他也提到basename了,这在这里很有用。

有了这一切,这就是我要做的事情。当您需要对脚本进行一些更改并尝试记住您过去的逻辑时,您可能只会在几个月后欣赏一些更改。

#!/bin/bash

if [ "$#" != 2 ]; then
    echo "Usage: $0 directory prefix" >&2
    echo "Put a prefix to all the files in a directory." >&2
    exit 1
else
    directory="$1"
    prefix="$2"
    if [ -d "$directory" ]; then
        for f in "$directory"/* ; do
            base=$(basename "$f")
            if [ -f "Sdirectory/$prefix.$base" ] ; then
                echo "This would overwrite $prefix.$base; exiting" >&2
                exit 1
            else
                mv -v "$directory/$base" "$directory/$prefix.$base"
            fi
       done
    else
       echo "$directory is not a directory" >&2
    fi
fi

推荐阅读