1

I'm quite new to bash scripting and I've ran out of ideas in my homework script.

The script takes 4 arguments - pathToDirectory, [-c/-m/-r] == copy/move/remove, ext1 and ext2 (example of running a script: script.sh /home/user/somefolder -c a.txt b.sh ).

The script should find all files in /home/user/someFolder (and its all subfolders) that contain 'a.txt' in their names and (in -c and -m case) rename that 'a.txt' part to 'b.sh' and depending on -c/-m argument either create a new file or just rename an existing file (in -r case it just removes the file) and then write in stdout something like 'old name => new name'.

example output of a script mentioned above:
/home/user/someFolder/bbb.txt => /home/user/someFolder/bba.txt

Well, that was not a problem to implement, everything worked until I posted my code to our upload system (evaluates our script).

The very first Upload System's try to run my script looked like "script.sh /something/graph 1 -c .jpg .jpeg".

The problem now is, that the whole '/something/graph 1' is a path and that whitespace before '1' ruins it all.

expected output: ./projekty/graph 1.jpg => ./projekty/graph 1.jpeg
my script output: ./projekty/graph => ./projekty/graph.jpeg 1.jpg => 1.jpeg

What I have so far:

if [ "$2" = "-r" ]; then
    for file in  $(find $1 -name "*$3"); do
        echo $file
        rm -f $file
    done    

elif [ "$2" = "-c" ]; then
    for file in  $(find "$1" -name "*$3") ; do      
        cp "$file" "${file//$3/$4}"
        echo $file "=>" ${file%$3}$4            
    done

elif [ "$2" = "-m" ]; then
    for file in  $(find $1 -name "*$3"); do
        mv "$file" "${file//$3/$4}"
        echo $file "=>" ${file%$3}$4        
    done    

else    
    echo Unknown parameter >&2
fi

My tried&notworking&probablystupid idea: as the -r/-c/-m parameter should be at $2, I was able to detect that $2 is something else (assumpting something that still belongs to the path) and append that $2 thing to $1, so then I had a variable DIR which was the whole path. Using shift I moved all parameters to the left (because of the whitespace, the -r/-m/-c parameter was not on $2 but on $3, so I made it $2 again) and then the code looked like: (just the -c part)

DIR=$1
if [ "$2" != "-r" ] && [ "$2" != "-c" ] && [ "$2" != "-m" ]; then
     DIR+=" $2"
     shift      
fi

if [ "$2" = "-c" ]; then
    for file in  $(find "$DIR" -name "*$3") ; do        
        cp "$file" "${file//$3/$4}"
        echo $file "=>" ${file%$3}$4            
    done    
fi

when i echoed "$DIR", it showed the whole path (correctly), but it still didn't work.. Is there any other/better/any way how to fix this please ? :/

Thanks in advance !

1 Answer 1

1
  1. As the target string needs to be replaced only at the very end of a filename, "${file//$3/$4}" is a bad idea.

    Example: ./projekty/graph.jpg.jpg.jpg.graph.jpg

  2. Passing a string prone to unquoted expansion to a loop is a no better idea either.

    The fact is that find works as expected and its output looks like:

    ./projekty/graph 1.jpg
    

    But inside a loop it is expanded incorrectly:

    ./projekty/graph
    1.jpg
    

    To avoid this, you can save the output of find to a variable and then tokenize it until no text is left:

    list="$(find $1 -name "*$3")"
    
    while [ -n "$list" ]; do
        file="${list%%$'\n'*}"
        list="${list#$file}"
        list="${list#$'\n'}"
        # your commands here
        # ...
    done
    
Sign up to request clarification or add additional context in comments.

Comments

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.