I have problems with permissions using xargs with rm - linux

I have remove.txt file containing a.txt and b.txt as text. All files are in the same folder, I set chmod 777 for all those files. Now, when I run sudo cat remove.txt | xargs rm I get Permission denied for deletion of those two files listed in remove.txt. What am I doing wrong? I guess question now would be where to put sudo?

sudo cat remove.txt | xargs sudo rm

Related

Remove a file has the same name with folder after using tar

I created a script to find files, move them to a folder, compress this folder using tar. Then delete original folder. But after running the script, the folder was removed but a file having same name with the folder was created. I tried to run one by one command, it's OK. There is not this file. I added rm command in the script to remove it but not working.
I don't know why this file was create.
My script is below:
#!/bin/bash
cd /home/tuan/testrm/9/
mkdir compressdir
sudo find . -type f -name "*.txt" -print | xargs -I {} mv {} compressdir > /dev/null 2>&1 &
tar -cvzf compresslog.tar.gz --remove-files compressdir
mv compresslog.tar.gz compresslog-`date +"%d%m%Y"`.tar.gz
rm -rf compressdir
I want to know why this file was create and how to prevent this happen.
You should remove & at the end of sudo find line, and it will works.
Because of The & makes the command run in the background.
Root cause: the sudo find command line and tar -> mv -> rm run at synchronized.
If you had checked the file compresslog.tar.gz which the script generated, you will found that it was null or error, and the compress file contain the same content with someone file which you find.

One liner to copy folders (without files) from one location to another

I want to copy all the folders(without their respective content and sub-directories) from one directory to another.
My current relatively long solution is:
ls original/directory >> directory/to/copy/to/dirs.txt
cd directory/to/copy/to
xargs mkdir -p < dirs.txt
rm dirs.txt
You could do it like this
ls -d original/directory/* | xargs -I{} mkdir -p "directory/to/copy/to/{}"

bash rm to delete old files only deleting the first one

I'm using Ubuntu 16.04.1 LTS
I found a script to delete everything but the 'n' newest files in a directory.
I modified it to this:
sudo rm /home/backup/`ls -t /home/backup/ | awk 'NR>5'`
It deletes only one file. It reports the following message about the rest of the files it should have deleted:
rm: cannot remove 'delete_me_02.tar': No such file or directory
rm: cannot remove 'delete_me_03.tar': No such file or directory
...
I believe that the problem is the path. It's looking for delete_me_02.tar (and subsequent files) in the current directory, and it's somehow lost its reference to the correct directory.
How can I modify my command to keep looking in the /home/backup/ directory for all 'n' files?
Maybe find could help you do what you want:
find /home/backup -type f | xargs ls -t | head -n 5 | xargs rm
But I would first check what find would return (just remove | xargs rm) and check what is going to be removed.
The command in the backticks will be expanded to the list of relative file paths:
%`ls -t /home/backup/ | awk 'NR>5'`
a.txt b.txt c.txt ...
so the full command will now look like this:
sudo rm /home/backup/a.txt b.txt c.txt
which, I believe, makes it pretty obvious on why only the first file is removed.
There is also a limit on a number of arguments you can pass to rm, so
you better modify your script to use xargs instead:
ls -t|tail -n+5|xargs -I{} echo rm /home/backup/'{}'
(just remove echo, once you verify that it produces an expected results for you)
After the command substitution expands, your command line looks like
sudo rm /home/backup/delete_me_01.tar delete_me_02.tar delete_me_03.tar etc
/home/backup is not prefixed to each word from the output. (Aside: don't use ls in a script; see http://mywiki.wooledge.org/ParsingLs.)
Frankly, this is something most shells just doesn't make easy to do properly. (Exception: with zsh, you would just use sudo rm /home/backup/*(Om[1,-6]).) I would use some other language.

How to use ls command output in rm for a particular directory

I want to delete oldest files in a directory when the number of files is greater than 5. I'm using
(ls -1t | tail -n 3)
to get the oldest 3 files in the directory. This works exactly as I want. Now I want to delete them in a single command with rm. As I'm running these commands on a Linux server, cd into the directory and deleting is not working so I need to use either find or ls with rm and delete the oldest 3 files. Please help out.
Thanks :)
If you want to delete files from some arbitrary directory, then pass the directory name into the ls command. The default is to use the current directory.
Then use $() parameter expansion to transfer the result of tail into rm like this
rm $(ls -1t dirname| tail -n 3)
rm $(ls -1t | tail -n 3) 2> /dev/null
ls may return No such file or directory error message, which may cause rm to run unnessesary with that value.
With the help of following answer: find - suppress "No such file or directory" errors and https://unix.stackexchange.com/a/140647/198423
find $dirname -type d -exec ls -1t {} + | tail -n 3 | xargs rm -rf

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

Resources