1

I'm having an error trying to find a way to replace a string in a directory path with another string

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

The shell script

#!/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

i'm understanding that the rror it's in this line

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

but i don't know how to tell sh that treats $file variable as string and not as a directory object.

3
  • 1
    Probably: R2K_TEMP_DIR=$(echo $file |sed 's/"$R2K_SOURCE"/"$R2K_PROCESSED"/g') (although you could instruct find to find directories & files independently with -type f / -type d Commented Apr 25, 2013 at 19:05
  • @Wrikken it's works now write that like an answer and y will approve your answer. Thanks a lot Commented Apr 25, 2013 at 19:09
  • Loetar's answer is more correct then my quick remark ;) Commented Apr 25, 2013 at 19:12

2 Answers 2

8

If you want ot replace part of path name you can echo path name and take it to sed over pipe. Also you must enable globbing by placing sed commands into double quotes instead of single and change separator for 's' command like that:

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

Then you will be able to operate with slashes inside 's' command.

Update:

Even better is to remove useless echo and use "here is string" instead:

R2K_TEMP_DIR=$(sed "s:$R2K_SOURCE:$R2K_PROCESSED:g" <<< "$file")
Sign up to request clarification or add additional context in comments.

Comments

4

First, don't use:

for item in $(find ...)

because you might overload the command line. Besides, the for loop cannot start until the process in $(...) finishes. Instead:

find ... | while read item

You also need to watch out for funky file names. The for loop will cough on all files with spaces in them. THe find | while will work as long as files only have a single space in their name and not double spaces. Better:

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

This will put nulls between file names, and read will break on those nulls. This way, files with spaces, tabs, new lines, or anything else that could cause problems can be read without problems.

Your sed line is:

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

What this is attempting to do is edit your $file which is a directory. What you want to do is munge the directory name itself. Therefore, you have to echo the name into sed as a pipe:

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

However, you might be better off using environment variable parameters to filter your environment variable.

Basically, you have a directory called source/ and all of the files you're looking for are under that directory. You simply want to change:

 source/foo/bar

to

 processed/foo/bar

You could do something like this ${file#source/}. The # says this is a left side filter and it will remove the least amount to match the glob expression after the #. Check the manpage for bash and look under Parameter Expansion.

This, you could do something like this:

#!/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/}" removes the source/ from the start of $file and you merely prepend processed/ in its place.

Even better, it's way more efficient. In your original script, the $(..) creates another shell process to run your echo in which then pipes out to another process to run sed. (Assuming you use loentar's solution). You no longer have any subprocesses running. The whole modification of your directory name is internal.

By the way, this should also work too:

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

I just didn't test that.

2 Comments

using this kind of string substitution ´R2K_TEMP_DIR="$R2K_PROCESSED/${file#$R2K_SOURCE}"´ how can i remove file extention from the filepath based on a extension patters ex (.mib,.MIB,.my) etc.. my last attempt it's R2K_NEW_FILE="${$R2K_TEMP_DIR%$MIB_EXTENTIONS}" where MIB_EXTENTION=".mib|.MIB|.my"
These are globs and not regular expressions. You could do ${file%.*} and that will remove all extensions. You could also do ${file%.*(mib|MIB|my)} to remove only certain expressions. Note that it's *(ext1|ext2|ext3), and in BASH, you have to shopt -s extglob in order to use these extended expressions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.