-1

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 ?

Ahmet Sait
  • 21
  • 7
  • Read this from a sister site, super detailed: https://unix.stackexchange.com/questions/9496/looping-through-files-with-spaces-in-the-names – Nic3500 Nov 09 '17 at 20:53
  • This is [BashPitfalls #1](http://mywiki.wooledge.org/BashPitfalls#for_i_in_.24.28ls_.2A.mp3.29); also the subject of [Using Find](http://mywiki.wooledge.org/UsingFind) and *numerous* dupes here on SO (no need to refer over to unix.se)! – Charles Duffy Nov 09 '17 at 21:08
  • @CharlesDuffy Well thanks for the heads up but I don't see why would this question get downvoted -cuz I don't know shell scripting? – Ahmet Sait Nov 09 '17 at 21:14
  • While the downvote wasn't mine, the one thing I think you *could* have done differently is running your code through http://shellcheck.net/ before asking the question, as advised by the [`bash` tag wiki](https://stackoverflow.com/tags/bash/info); the wiki links given in the warnings -- such as [SC2044](https://github.com/koalaman/shellcheck/wiki/SC2044) -- address the problem. – Charles Duffy Nov 09 '17 at 21:22
  • @CharlesDuffy I did, (by locally installing spellcheck) but it suggested me to use `find -exec` which I couldn't manage to do. – Ahmet Sait Nov 09 '17 at 21:26
  • Did you read the wiki associated with that shellcheck warning? It shows how to use `find -print0` (as the answer by janos does as well). – Charles Duffy Nov 09 '17 at 21:33

1 Answers1

1

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.)

janos
  • 120,954
  • 29
  • 226
  • 236
  • (re: an attack no longer possible now that this answer is edited to use NUL-delimited output) ...as a concrete attack, consider `d=$'./foo/ \n/etc\n/'; mkdir -p "$d" && touch "$d/f"` before this script is run; you presumably don't want `/etc` to have its `+x` permissions removed. – Charles Duffy Nov 09 '17 at 21:06