Using mtime other than with FIND - unix

I am trying to write a script which will move files older than 1 day to an archive directory. I used the following find command:
for filename in `find /file_path/*.* -type f -mtime +1`
This fails since my argument list is too big to be handled by find. I got the following error:
/usr/bin/find: arg list too long
Is it possible to use find in an IF-ELSE statement? Can someone provide some examples of using mtime other then in find.
Edit: To add the for loop of which the find is a part.

find /file_path -name '*.*' -mtime +1 -type f |
while read filename
do ...move operation...
done
That assumes your original code was acceptable in the way it handled spaces etc in file names,
and that there is no sensible way to do the move in the action of find. It also avoids problems with overlong argument lists.

Why not just use the -exec part of find?

If you just want to cp files, you could use
find /file_path -name "." -mtime +1 -type f | xargs -i mv {} /usr/local/archived

Related

Is it possible remove the root directory from find command output?

I want to move some files around and thought that find would be a good option to select the correct files. So I look for the files:
find somedir -iname "somefile"
somedir/subdir1/subdir2/somefile
somedir/subdir2/somefile
somedir/subdir3/somefile
somedir/subdir4/somefile
somedir/subdir5/somefile
Thats not very helpful for what I'm planning next. What I need would be:
find somedir -iname "somefile" -magic-option
subdir1/subdir2/somefile
subdir2/somefile
subdir3/somefile
subdir4/somefile
subdir5/somefile
What would -magic-option be?
Obviously a simple printout is not what I had in mind. The final command will also have a '-exec'. Something like:
find somedir -iname "somefile" -magic-option -exec some_command 'somedir/{}' 'someotherdir/{}' ';'
I'm surprised I couldn't find anything as removing the root directory from the result seem a pretty obvious feature.
If the answer to the question is 'NO' then that's ok. I have a crude plan B using pushd and for loops. But find would be more elegant.
It is non-standard, but with gnu find (4.6.0.225-235f), you could do:
find somedir -iname somefile -printf %P\\n
From the documentation:
%P File's name with the name of the starting-point under which it was found removed.
If you want a generic solution, it seems simple enough to filter the output with something like:
find somedir -iname somefile | sed 's#^[^/]*/##'
Both of those solutions will fail horribly if any of your filenames contain a newline, so if you want a robust solution you would want to do something like:
find somedir -iname somefile -printf %P\\0
Looks like you need the mindepth flag.
find somedir -mindepth 2 -iname "somefile"
This will ignore the directory you are in and search from one level down recursively.

List only folders which matches the wildcard expression

Is there a command which lists all folders that matches a wildcard expression? Example, if there are thousands of directories and I only want those ending in M or those starting in JO to be listed, can I do that with a certain Linux command? Thanks!
Use find command, for example:
# find anything that start with 'jo' end with 'm' (case insensitive)
find . -iname 'jo*m'
You can execute any command after that, for example:
# find just like above but case sensitive, and move them to `/tmp`
find . -name 'JO*M' -exec mv -v {} /tmp \;
To find only a directory, you can use -type d flag, for example:
# find any directory that start with JO
find . -name 'JO*' -type d
Explanation, first argument is the starting directory, . means current directory. The next argument means the search criteria -name for case sensitive search, -iname for case insensitive search, -type for type of item search, -exec to execute certain command where the {} is the file name matched. You can learn more here or for your specific case here.

unix command to change directory name

Hi this is a simple question but the solution eludes me at the moment..
I can find out the folder name that I want to change the name of, and I know the command to change the name of a folder is mv
so from the current directory if i go
ls ~/relevant.directory.containing.directory.name.i.want.to.change
to which i get the name of the directory is called say lorem-ipsum-v1-3
but the directory name may change in the future but it is the only directory in the directory:
~/relevant.directory.containing.directory.name.i.want.to.change
how to i programmatically change it to a specific name like correct-files
i can do it normally by just doing something like
mv lorem-ipsum-v1-3 correct-files
but I want to start automating this so that I don't need to keep copying and pasting the directory name....
any help would be appreciated...
Something like:
find . -depth -maxdepth 1 -type d | head -n 1 | xargs -I '{}' mv '{}' correct-files
should work fine as long as only one directory should be moved.
If you are absolutely certain that relevant.directory.containing.directory.name.i.want.to.change only contains the directory you want to rename, then you can simply use a wildcard:
mv ~/relevant.directory.containing.directory.name.i.want.to.change/*/ ~/relevant.directory.containing.directory.name.i.want.to.change/correct-files
This can can also be simplified further, using bash brace expansion, to:
mv ~/relevant.directory.containing.directory.name.i.want.to.change/{*/,correct-files}
cd ~/relevant.directory.containing.directory.name.i.want.to.change
find . -type d -print | while read a ;
do
mv $a correct-files ;
done
Caveats:
No error handling
There may be a way of reversing the parameters to mv so you can use xargs instead of a while loop, but that's not standard (as far as I'm aware)
Not parameterised
If there any any subdirectories it won't work. The depth parameters on the find command are (again, AFAIK) not standard. They do exist on GNU versions but seem to be missing on Solaris
Probably others...

Find/grep statement code filter

I need to generate a list of IFS files that contain a given string
("iim"). (IFS is the IBM System i database) I need to search directory /linoma/goanywhere/projects
recursively. I've been able to do this with a combination of the FIND
and GREP commands in QSHELL:
find /linoma/goanywhere/userdata/projects -type f -exec grep -lRF "iim"
'{}' ';'
Here's the rub: there is a subdirectory I want to ignore
(/linoma/goanywhere/userdata/projects/demo). How would I modify my
find/grep statement to exclude the demo folder?
find /linoma/goanywhere/userdata/projects -( -type f -and -not -path '/linoma/goanywhere/userdata/projects/demo/**' -) -exec grep -IRF 'iim' '{}' ';'
should work for GNU find, I believe. If your local find doesn't support that syntax, you might also brute-force remove by appending | grep -v /linoma/goanywhere/userdata/projects/demo

UNIX find: opposite of -newer option exists?

I know there is this option for unix's find command:
find -version
GNU find version 4.1
-newer file Compares the modification date of the found file with that of
the file given. This matches if someone has modified the found
file more recently than file.
Is there an option that will let me find files that are older than a certain file. I would like to delete all files from a directory for cleanup. So, an alternative where I would find all files older than N days would do the job too.
You can use a ! to negate the -newer operation like this:
find . \! -newer filename
If you want to find files that were last modified more then 7 days ago use:
find . -mtime +7
UPDATE:
To avoid matching on the file you are comparing against use the following:
find . \! -newer filename \! -samefile filename
UPDATE2 (several years later):
The following is more complicated, but does do a strictly older than match. It uses -exec and test -ot to test each file against the comparison file. The second -exec is only executed if the first one (the test) succeeds. Remove the echo to actually remove the files.
find . -type f -exec test '{}' -ot filename \; -a -exec echo rm -f '{}' +
You can just use negation:
find ... \! -newer <reference>
You might also try the -mtime/-atime/-ctime/-Btime family of options. I don't immediately remember how they work, but they might be useful in this situation.
Beware of deleting files from a find operation, especially one running as root; there are a whole bunch of ways an unprivileged, malicious process on the same system can trick it into deleting things you didn't want deleted. I strongly recommend you read the entire "Deleting Files" section of the GNU find manual.
If you only need files that are older than file "foo" and not foo itself, exclude the file by name using negation:
find . ! -newer foo ! -name foo
Please note, that the negation of newer means "older or same timestamp":
As you see in this example, the same file is also returned:
thomas#vm1112:/home/thomas/tmp/ touch test
thomas#vm1112:/home/thomas/tmp/ find ./ ! -newer test
./test
Unfortunately, find doesnt support this
! -newer doesnt mean older. It only means not newer, but it also matches files that have equal modification time. So I rather use
for f in path/files/etc/*; do
[ $f -ot reference_file ] && {
echo "$f is older"
# do something
}
done
find dir \! -newer fencefile -exec \
sh -c '
for f in "$#"; do
[ "$f" -ot fencefile ] && printf "%s\n" "$f"
done
' sh {} + \
;

Resources