how to change chmod of directories in path - linux

Q How to set chmod of a/ a/b/ a/b/c/ & a/b/c/d/ to 755
Say I have a path a/b/c/d/ to create
I can call mkdir -p a/b/c/d/ and it will create each of the directory in path
Now I want to set chmod of a/ a/b/ a/b/c/ & a/b/c/d/ to 755
Note mkdir -pm 0755 a/b/c/d/ will set chmod to 755 for only the last folder

Use:
(umask 022; mkdir -p /a/b/c/d)
Setting the umask ensures that the write bits are reset for group and other on any directories the command creates (but has no effect on pre-existing directories, of course). The directories are then created with 755 permissions as desired. The parentheses use a sub-shell so that only the mkdir command is affected by the umask setting. (I use umask 022 by default; I usually don't mind people reading files, but I don't like them changing them without my permission.)

In case the directories are already created, you can change the permissions with this bash snippet:
path=a/b/c/d
while [[ -n $path ]]; do
chmod 755 $path
path=${path%[^/]*}
done

perldoc -f chmod
chmod LIST
Changes the permissions of a list of files. The first element of the list must be the numeric mode, which should probably be an octal number, and which definitely should not be a string of octal digits: 0644 is okay, but "0644" is not. 
Try something like this:
chmod 0777, "test.txt";
Note
Note chmod is a LIST operator meaning you can pass it a list (or array) like this:
$cnt = chmod 0755, "foo", "bar";

If you are presently in parent directory of 'a' we could probably do this
chmod 755 a ; find a/ -type d -exec chmod 755 {} \;

path=a/b/c/d/
while [[ -n $path ]]; do
chmod 755 $path
path=${path%/*}
done
buff's answer doesn't work for me. Here's modification to his answer that does work. Substring removal fixed, and with this approach original path should end with trailing / .

Related

Change permissions for each directory in a path using bash

I am trying to change the permissions for each directory in a path that a user will specify. This will be completed in a bash script. For example:
DIR = /a/b/c/d/e/f/
chmod 777 /a/b/c/d/e/f/
chmod 777 /a/b/c/d/e/
chmod 777 /a/b/c/d/
chmod 777 /a/b/c/
chmod 777 /a/b/
chmod 777 /a/
777 is only an example. Solution should allow for any permissions.
I do not want to change permissions of files within the directories and I can not assume these are the only sub-directories. I only want to change the permissions that are explicitly in the path given by the user.
The obvious way is to start at the deepest point, and iterate upwards using dirname in a loop:
perms=a+rX
d=a/b/c/d/e/f
while [ "$d" != . ]
do
chmod $perms "$d"
d=$(dirname "$d")
done
This is all portable shell, so doesn't depend on Bash - any POSIX-compliant shell will suffice.
I've used relative directory names, as you really don't want to be changing permissions of / on a real system.
You could of course just use a substitution expansion instead of invoking
dirname if you want: d=${d%/*}.
Are you sure you want to set 777 on some directories ?
Anyway, you can achieve this with dirname and recurse on $DIR until the root directory:
DIR=/a/b/c/d/e/f/
while [[ $DIR =~ /.+ ]] ;do
chmod 777 $DIR
DIR=$(dirname $DIR)
done

Granting my access permissions to everyone?

If folder folder is read/write/execute accessible to me, then it should become read/write/execute to everyone.
Calling chmod -R 777 ./folder does not suit, because it makes all files executable, even those that were not executable before.
Is there an easy way?
You could do it with UNIX find combined with the exec flag to run a chmod command on every file that matches a filter, and filter on the executable bit.
e.g.
first find the non executable files recursively and change them to all RW
find ./folder -not -executable -exec chmod a=rw {} \;
then find all the executable ones recursively and change them to all RWX
find ./folder -executable -exec chmod a=rwx {} \;
You might want to add add the files in the folder to a user group like everyone or users depending on your distro.
chown -R <youruser>:everyone ./folder
You can check what available user groups you have with groups command.

Sync file permissions *only*

A junior team member did a nasty chmod -R 777 in /etc/ and cause SSH cannot login remotely in a Ubuntu server. Now I fixed this login issue by manually set the correct file permissions on /etc/ssh/*, /etc/sudoers, /etc/ssl/* by comparing other normal system. But there are so many other files which may cause future issues.
I am thinking to use rsync to do the work, but don't want it to sync file contents, just permissions, no more work.
Is that possible? I see rsync has -a option but it does too much.
If you have the "normal" content of /etc available on the same system (like mounted in some other directory, let's say /mnt/correct/etc), you could use the --reference parameter to chmod and chown commands, and combine it with find that is started from the "normal" directory:
$ cd /mnt/correct/etc
$ find . ! -type l -exec chown -v --reference='{}' /etc/'{}' \;
$ find . ! -type l -exec chmod -v --reference='{}' /etc/'{}' \;
(I'm assuming you're on a UNIX system with GNU coreutils versions of chmod and chown.)
The "! -type l" condition in find excludes symbolic links, because otherwise chmod will use the link's permissions to change the file the link points to (and same applies to chown).
Please note you can also try something that won't necessarily make you need to copy files from one place to another (depending on the filesize it may be desired)
You could use a mix of find and some grepping to generate a shell script to be executed on the host where you need to fix permissions.. you could use the same approach to generate a script for changing users/groups as well.. for example:
# find . -printf 'chmod %m %p #%M\n' | sort -k3 | grep -Pi '\s+\S*s\S*$' > /var/tmp/fix_permissions.bash
# bash /var/tmp/fix_permissions.bash
In the example above, what it does is to list all the files with their attributes in this format:
chmod 2755 ./addfs_7.1.0/bin #drwxr-sr-x
chmod 2755 ./addfs_7.1.0/config #drwxr-sr-x
chmod 2755 ./addfs_7.1.0 #drwxr-sr-x
chmod 2755 ./addfs_7.1.0/install #drwxr-sr-x
chmod 2755 ./addfs_7.1.0/library.dda #drwxr-sr-x
chmod 2755 ./addfs_7.1.0/library #drwxr-sr-x
chmod 2755 ./autosimimport #drwxr-sr-x
And in my case I only want to sync those with the 's' flag, so I filter with grep -Pi '\s+\S*s\S*$'. Sort was there as well because I had to compare the files in the other host.
TLDR
If you just want to apply all the permissions with no filtering or comparing:
Create a script with the correct permissions on the "base" host
find . -printf 'chmod %m %p\n' > /var/tmp/fix_permissions.sh
Execute the script in the other host
bash /var/tmp/fix_permissions.sh

Copying files with wildcard (*) to a folder in a bash script - why isn't it working?

I am writing a bash script that creates a folder, and copies files to that folder. It works from the command line, but not from my script. What is wrong here?
#! /bin/sh
DIR_NAME=files
ROOT=..
FOOD_DIR=food
FRUITS_DIR=fruits
rm -rf $DIR_NAME
mkdir $DIR_NAME
chmod 755 $DIR_NAME
cp $ROOT/$FOOD_DIR/"*" $DIR_NAME/
I get:
cp: cannot stat `../food/fruits/*': No such file or directory
You got that exactly backwards -- everything except the * character should be double-quoted:
#!/bin/sh
dir_name=files
root=..
food_dir=food
fruits_dir=fruits
rm -rf "$dir_name"
mkdir "$dir_name"
chmod 755 "$dir_name"
cp "$root/$food_dir/"* "$dir_name/"
Also, as a matter of best-practice / convention, non-environment variable names should be lower case to avoid name conflicts with environment variables and builtins.

Bash test and execute if directory pattern exists

How do you do an inline test for the existence of a directory pattern?
If a directory pattern exists, then I want to chmod that pattern.
e.g. I'm trying to do the following:
[ -d /usr/local/myproject/*/bin ] && chmod +x /usr/local/myproject/*/bin/*
but this gives me the error "-bash: [: too many arguments".
there's no need to test:
chmod +x /usr/local/myproject/*/bin/* 2>/dev/null
It doesn't work because -d test takes one argument. You seem to be passing more than one. A fix would be:
for dir in /usr/local/myproject/*/bin; do
[[ -d $dir ]] && chmod +x $dir/*
done
To salvage some usefulness out of my answer, just suppose you had too many bin directories that you couldn't do it yi_H's way.
find /usr/local/myproject/ -path '/usr/local/myproject/*/bin' -maxdepth 2 -type d -exec chmod a+x {} + 2>/dev/null

Resources