Wednesday, April 27, 2022

[SOLVED] I can't seem to pass arguments with spaces in bash script

Issue

I was trying to write a script for normalizing permissions in Linux:

for f in $(find . -type f); do
    file "$f" | grep -e "ELF 64-bit LSB executable" -e "ELF 32-bit MSB executable" > /dev/null
    if [ $? = 0 ]; then
        chmod -c u=rwx,g=rx,o=rx "$f"
    else
        chmod -c u=rw,g=r,o=r "$f"
    fi;
done

Obviously, I'm trying to pass file paths to chmod and I'm using double quotes as in "$f" but somehow still getting No such file or directory errors:

chmod: './FreeDesktop_integration/nautilus-scripts/Archiving/PeaZip/Extract''e erişilemedi: Böyle bir dosya ya da dizin yok
chmod: 'Archive''e erişilemedi: Böyle bir dosya ya da dizin yok

It seems ./FreeDesktop_integration/nautilus-scripts/Archiving/PeaZip/Extract Archive gets treated as 2 files by chmod (and this is rather unexpected).

So what's causing this and how do I solve this (passing args properly) ?

Bonus question: Is there a better way of doing what I'm trying to achieve with the script ?


Solution

In for f in $(find . -type f), the shell performs word-splitting on the output of the find command. This way it's not safe to use it like you did.

You can make it safe by using a while loop instead:

find . -type f -print0 | while IFS= read -r -d '' f; do
    if file "$f" | grep -qe "ELF 64-bit LSB executable" -e "ELF 32-bit MSB executable"; then
        chmod -c u=rwx,g=rx,o=rx "$f"
    else
        chmod -c u=rw,g=r,o=r "$f"
    fi
done

(I also simplified the conditional a bit, along with a bunch of tips from @CharlesDuffy.)



Answered By - janos
Answer Checked By - David Marino (WPSolving Volunteer)