Need to touch a file in several directories using one liner in linux - linux

I have lots of directories. I need to cd to all the directories and create 2 files. I tried doing this using xargs, but I couldn't do it. Can you please tell me how to achieve this?

If you don't want or need to run find but have a list of directories, something like this:
xargs -i touch {}/a {}/b <directories.txt
If the directory paths are completely regular (e.g. all subdirectories two levels down), it might be as easy as
touch */*/a */*/b

find <path> -type d -exec touch {}/a {}/b \;
path may be . if you are already in the top directory you are interested to work on.

Related

How to copy recursive directories to a flat directory

I am trying to copy all the *.psd files, currently in a multi directories structure, into one single directory.
Is there an rsync parametrization to allow it?
The solution proposed at Copying files from multiple directories into a single destination directory is not a multilevel recursive directories, only single level subdirectories.
In my current case I have files in multiple recursive directories (up to 7 levels) that I would like to reconcile in a single directory.
I fear rsync can't help you here. You can use find to find all the files and copy them to the destination directory, though:
find /path/to/source/topdir -type f -name '*.psd' -exec cp {} /path/to/destination/ \;
In my opinion #choroba's answer is the right one.
For completeness (or if for any reason you needed the files to be copied with rsync) you can do something way less efficient using rsync (which is just like using cp in this case), using find, a loop and other things not really necessary.
for file in $(find ./path/to/source/topdir -name "*psd" ); do rsync $file /path/to/destination/; done

How to loop through subdirectories in a bash script?

Suppose I'm in a directory, dir1. Within that directory I have myscript.sh and a directory subdir1. subdir1 has several subsub directories, subsub1, subsub2, subsub3. Within each of those subsub directories is a bash script all named script2.sh, and I want to run each one of them.
First, I just want to make sure I can print all the subsub directories.
I have:
for dir in /subdir1/*/ ; do
echo $dir
done
Can anyone tell me what I'm doing wrong?
I guess you could run them this way:
find subdir1 -type f -name "NAME_OF_YOUR_SCRIPT.sh" -exec {} \;
You are going to run into issues if any of the directories have spaces or other special characters in the names.
Based on what you provided
for scriptfile in ./subdir/*/*script2.sh
do
/bin/sh $scriptfile
done
may work best for you.
To deal with spaces or other special characters in your directory names, you'll want to use find and pass the output to xargs.

Using Perl how can I clean up left over directories with no files?

There is a specific directory which is used as a temp/scratch directory by some program.
E.g. /a/b/c/work
Under work multiple hierarchical directories may exist e.g.
/a/b/c/work/
\d1/
\d1.1
\d2
\d2.2
What I want is to clean up this work directory as there are left over files that take space.
Essentially I need to delete all subdirectories under work that the leaf directory is empty.
So if d1.1 is empty but d2.2 has files then delete everything under d1 (including d1) but not d2.
What is the cleanest/standard way to do this in perl?
I thought to use a solution with backticks e.g. rm -rf etc but I thought there could be some better way than coding sequences of ls folowed by rm
Note: Just to be clear. I want a solution in Perl as this is not a one time thing and I dont want to do this manually each time
If you use find command this way you can achieve it.
find /path/to/dir -empty -type d -delete
Where,
-empty Only find empty files and make sure it is a regular file or a directory.
-type d Only match directories.
-delete Delete files.
Always put -delete option at the end of find command as find command line is evaluated as an expression, so putting -delete first will make find try to delete everything below the starting points you specified.
To automate this in shell script follow below code:
path=`pwd`
find $path -empty -type d -delete
or you can give certain input as arguments of shell script like myShell.sh /path/to/mydir in that case the following code will be do the work,
$path=$1
find $path -empty -type d -delete
As for if you really want to go for perl you can find your answer as follows
use strict;
use warnings;
use File::Util;
my $path = '...';
my $fu = File::Util->new();
my #all_dirs = $fu->list_dir($path, '--recurse', '--dirs-only');
my #empty_dirs = grep { not $fu->list_dir($_) } #all_dirs;
also a short method
perl -MFile::Find -e"finddepth(sub{rmdir},'.')"
which is explained very good here.

sed not working as expected, but only for directory depth greater than 1

I am trying to find all instances of a string in all files on my system up to a specified directory depth. I then want to replace these with another string and I am using 'find' and 'sed' by piping one into the other.
This works where I use the base path as cd /home/../.. or any other directory which isn't "/". It also only works if I select a directory depth of 1 (so /test.txt is changed, but /home/test.txt isn't) If I change nothing else and used say a depth of 2 or 3, neither /test.txt nor /home/text.txt are changed. In the former, no warnings appear, and in the latter, the results below (And no strings are replaced in either of the files).
Worryingly, it did work once out of the blue, but I have no idea how and I can't recreate the results. I should say I know the risks of using these commands with root from base directory, and the specific use of the programs below is intentional so I am not looking for an alternative way, just a clue as to how this isn't working and perhaps a suggestion on how to fix it.
cd /;find . -maxdepth 3 -type f -print0 | xargs -0 sed -i 's/teststring123/itworked/gI'
sed: couldn't open temporary file ./sys/kernel/sedoPGqGB: No such file or directory
sed: couldn't open temporary file ./proc/878/sedtqayiq: No such file or directory
As you see, there are warnings, but nether the less I would expect it to work, the commands appear good, anything I am missing folks?
This should be:
find / -maxdepth 3 -type f -print -exec sed -i -e 's/teststring123/itworked/g' {} \;
Although changing all files below / strikes me as a very bad idea indeed (I hope you're not running as root!).
The "couldn't open temporary file ./[...]" errors are likely to be because sed, running as your user, doesn't have permission to create files in /.
My version runs from your current working directory, I assume your ${HOME}, where you'll be able to create the temporary file, but you're still unlikely to be able to replace those files vital to the continued running of your operating system.

Bash script to recursively step through folders and delete files

Can anyone give me a bash script or one line command i can run on linux to recursively go through each folder from the current folder and delete all files or directories starting with '._'?
Change directory to the root directory you want (or change . to the directory) and execute:
find . -name "._*" -print0 | xargs -0 rm -rf
xargs allows you to pass several parameters to a single command, so it will be faster than using the find -exec syntax. Also, you can run this once without the | to view the files it will delete, make sure it is safe.
find . -name '._*' -exec rm -Rf {} \;
I've had a similar problem a while ago (I assume you are trying to clean up a drive that was connected to a Mac which saves a lot of these files), so I wrote a simple python script which deletes these and other useless files; maybe it will be useful to you:
http://github.com/houbysoft/short/blob/master/tidy
find /path -name "._*" -exec rm -fr "{}" +;
Instead of deleting the AppleDouble files, you could merge them with the corresponding files. You can use dot_clean.
dot_clean -- Merge ._* files with corresponding native files.
For each dir, dot_clean recursively merges all ._* files with their corresponding native files according to the rules specified with the given arguments. By default, if there is an attribute on the native file that is also present in the ._ file, the most recent attribute will be used.
If no operands are given, a usage message is output. If more than one directory is given, directories are merged in the order in which they are specified.
Because dot_clean works recursively by default, use:
dot_clean <directory>
If you want to turn off the recursively merge, use -f for flat merge.
dot_clean -f <directory>
find . -name '.*' -delete
A bit shorter and perform better in case of extremely long list of files.

Resources