1

我在尝试找到将目录路径中的字符串替换为另一个字符串的方法时出错

sed: Error tryning to read from {directory_path}: It's a directory 

外壳脚本

#!/bin/sh

R2K_SOURCE="source/"
R2K_PROCESSED="processed/"
R2K_TEMP_DIR=""

echo " Procesando archivos desde $R2K_SOURCE "

for file in $(find $R2K_SOURCE )
do
        if [ -d $file ]
        then
                R2K_TEMP_DIR=$( sed 's/"$R2K_SOURCE"/"$R2K_PROCESSED"/g' $file )
                echo "directorio $R2K_TEMP_DIR"
        else
#               some code executes
                :
        fi
done

# find $R2K_PROCCESED -type f -size -200c -delete

我知道它在这条线上的错误

R2K_TEMP_DIR=$( sed 's/"$R2K_SOURCE"/"$R2K_PROCESSED"/g' $file )

但我不知道如何告诉 sh 将 $file 变量视为字符串而不是目录对象。

4

2 回答 2

8

如果您想替换部分路径名,您可以回显路径名并将其带到管道上的 sed。此外,您必须通过将 sed 命令放入双引号而不是单引号来启用通配符,并更改 's' 命令的分隔符,如下所示:

R2K_TEMP_DIR=$(echo "$file" | sed "s:$R2K_SOURCE:$R2K_PROCESSED:g")

然后您将能够在“s”命令中使用斜杠进行操作。

更新:

更好的是删除无用的回声并改用“这里是字符串”:

R2K_TEMP_DIR=$(sed "s:$R2K_SOURCE:$R2K_PROCESSED:g" <<< "$file")
于 2013-04-25T19:07:59.037 回答
4

首先,不要使用:

for item in $(find ...)

因为您可能会使命令行超载。$(...)此外,直到进程完成,for 循环才能开始。反而:

find ... | while read item

您还需要注意时髦的文件名。该for循环将对所有带有空格的文件进行咳嗽。只要find | while文件的名称中只有一个空格而不是两个空格,它们就可以工作。更好的:

find ... -print0 | while read -d '' -r item

这将在文件名之间放置空值,read并将在这些空值上中断。这样,可以毫无问题地读取带有空格、制表符、新行或任何其他可能导致问题的文件。

您的 sed 行是:

R2K_TEMP_DIR=$( sed 's/"$R2K_SOURCE"/"$R2K_PROCESSED"/g' $file )

这是试图做的是编辑你$file的目录。您想要做的是调整目录名称本身。因此,您必须将名称sed作为管道回显:

R2K_TEMP_DIR=$(echo $file | sed 's/"$R2K_SOURCE"/"$R2K_PROCESSED"/g')

但是,您最好使用环境变量参数来过滤您的环境变量。

基本上,您有一个名为的目录source/,您要查找的所有文件都在该目录下。你只是想改变:

 source/foo/bar

 processed/foo/bar

你可以做这样的事情 ${file#source/}。#表示这是一个左侧过滤器,它将删除最少的数量以匹配#. 检查手册页bash并在Parameter Expansion下查找。

这个,你可以做这样的事情:

#!/bin/sh

R2K_SOURCE="source/"
R2K_PROCESSED="processed/"
R2K_TEMP_DIR=""

echo " Procesando archivos desde $R2K_SOURCE "

find $R2K_SOURCE -print0 | while read -d '' -r file
do
    if [ -d $file ]
    then
        R2K_TEMP_DIR="processed/${file#source/}"
        echo "directorio $R2K_TEMP_DIR"
    else
#       some code executes
        :
    fi
done

R2K_TEMP_DIR="processed/${file#source/}"source/从一开始就删除了$file,你只是processed/在它的位置前面加上。

更好的是,它的效率更高。在您的原始脚本中,$(..)创建另一个 shell 进程来运行您echo的,然后通过管道输出到另一个进程来运行sed。(假设您使用loentar的解决方案)。您不再运行任何子流程。您的目录名称的整个修改是内部的。

顺便说一句,这也应该有效:

R2K_TEMP_DIR="$R2K_PROCESSED/${file#$R2K_SOURCE}"

我只是没有测试。

于 2013-04-25T19:54:33.530 回答