0

I am trying to change the permission to only read and write of all the files in a specific folder but the file has to have the string "DATA" in it.

I tried using this command but I'm not sure how to filter it should I use grep?

grep -nr DATA | chmod u=rw,g=rw,o=rw  *

3 Answers 3

1

As I said in the comments to your now deleted question on StackOverflow:

grep -rl DATA "foldername" | xargs -n1 chmod =rw 

... CAVEAT: this won't work if the filenames have spaces in them.

I strongly recommend reading a great deal of linux/unix toolchain tutorials and figuring out how tools work together before engaging with things in real life.

Your invocation changes EVERYTHING, but since chmod by default doesn't output anything, your grep does nothing.

What you really need to do is, as in my example, find the files that have DATA in them, and modify their permissions.

1
  • That's not limited to spaces. Other types of blanks, newline, single quotes, double quotes and backslashes would also be a problem. That would not work in zsh where =rw expands to the path of the rw command and chmod =rw is sensitive to the umask. Oct 21, 2023 at 8:24
0

You can recursively find each files in the directory an run chmod if a file contains string "DATA".

perm.sh:

#!/bin/bash

grep -w "DATA" "$1" && chmod 666 "$1"

Use find to recursively search for regular files (thanks Stephane)

find <path/of/folder> -type f -exec bash </path/of/perm.sh> {} \;
2
  • 1
    Note that [ -f also returns true for symlinks to regular files and both grep and chmod will act on the target of the symlink. So for instance if there's a symlink to /etc/shadow in there and /etc/shadow contains DATA and you're running that as root, you'll end up making /etc/shadow world writeable. Oct 21, 2023 at 8:47
  • Note that there's nothing bash-specific in that code (and you're using a .sh extension in the file). Using your system's sh would likely be more efficient and remove the need to install bash. sh and bash also support running inline scripts as in find ... -exec sh -c 'if ...' sh {} \; Oct 21, 2023 at 8:49
0

Since you're already using the GNU -r extension of grep¹, you could do:

grep -rlZ DATA . | xargs -r0 chmod a=rw

With -l, grep lists the files that contain at least one line matching the regexp. With -Z (also a GNU extension), it prints the file paths NUL-delimited so that output can be post-processed.

xargs -0² splits that output on NULs to pass as separate arguments to the chmod utility. With -r², xargs doesn't run chmod at all if its input is empty (grep didn't report any file path).

To skip the files which already have rw-rw-rw- permissions:

find . -type f ! -perm a=rw -exec grep -lZ DATA {} + |
  xargs -r0 chmod a=rw

Portably, you could do:

find . -type f \
       ! -perm a=rw \
       -exec grep -q DATA {} ';' \
       -exec chmod a=rw {} +

But as that runs one grep per file, that would be significantly less efficient.

In any case, having world writeable data files sounds like a very bad idea.

Also beware that chmod follows symlinks when changing the permissions of a file, so if a file is changed from being a regular file to a symlink to /etc/shadow or your ~/.bashrc (or for that matters if ./dir in ./dir/shadow is changed to a symlink to /etc) in between the time find finds the file and chmod is run, you could end up changing the permissions of the wrong file.

So you wouldn't want to run those commands in world-writeable directories.

If on a GNU/Linux system with zsh available, those issues can be avoided with:

find . -type f ! -perm a=rw -execdir zsh -c '
  zmodload zsh/system || exit
  for file do
    sysopen -o nofollow -u0 -- $file &&
      grep -q DATA &&
      chmod a=rw /dev/stdin
  done' {} +

Where find will take care of not following symlinks when descending the directory tree, and with -execdir the command (here zsh) is run from within the directory containing the found files. zsh takes care of opening the files without following symlinks (nofollow option), and /dev/stdin on Linux is a magic symlink to the file opened on /dev/stdin which should be guaranteed to point to the actual file that was opened even if it's been removed or renamed.


¹ some other greps now also support -r but few allow omitting the directory, which defaults to . in recent versions of GNU grep when -r/-R is also used.

² -r and -0 are also GNU extensions, but they're widespread in other implementations nowadays, and will even be in the next version of the POSIX standard.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .