I have started to use Linux and I'm practicing using/making codes to locate and do things. I need code that locates any file from a string of input.
Linux: Locating text file from a string input
filessearch
Related Solutions
The most straight forward way I can see to do this is with GNU find
, bash
and the sponge
utility from moreutils:
find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -print0 |
while IFS= read -rd '' file; do
echo 'cat path/to/theCommonComment.txt "$file" | sponge "$file"'
done
As it stands this will just print the cat
/sponge
commands without actually doing anything. Once you are sure you have what you want, you can remove the echo and the single quotes surrounding the command.
Without using sponge
or the -print0
option for find which may not be available on all systems:
find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -exec sh '
for file; do
tempfile=$(mktemp)
cat path/to/theCommonComment.txt "$file" >"$tempfile"
mv "$tempfile" "$file"
done
' sh {} +
There is no easy way to stop this one simply print what it will do, so be careful. One thing to watch out for - make sure your theCommonComment.txt
file is not in the directory you are doing the recursive operation in (or at least make sure that it is excluded from the find), or else you will end up with two of the headers in some files.
Update
A final thought is that you may want to check if the header has already been added to the file. This may be useful if you add new files and have to run the command again. It also gets around the problem of having the theCommonComment.txt
file in the search path. The two solutions would become:
comment_file=path/to/theCommonComment.txt
size=$(wc -c "$comment_file")
find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -print0 |
while IFS= read -rd '' file; do
if [ cmp -n "$size" $comment_file" "$file" ]; do
echo 'cat "$comment_file" "$file" | sponge "$file"'
fi
done
export comment_file=path/to/theCommonComment.txt
export size=$(wc -c "$comment_file")
find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -exec sh '
for file; do
if [ cmp -n "$size" $comment_file" "$file" ]; do
tempfile=$(mktemp)
cat "$comment_file" "$file" >"$tempfile"
mv "$tempfile" "$file"
fi
done
' sh {} +
If I understand correctly, you want to move files from the current directory and its subdirectories recursively to another directory, but only if the file
command reports them as “Microsoft Word” files. That is, you're interested in the files for which file "$filename" | grep 'Microsoft Word'
produces some output.
An easy way is to take things calmly and to it file by file. If you only want the files in the current directory, you can use a for
loop and a wildcard pattern:
for f in *.doc; do
if …
done
What's the condition? We want to test if Microsoft Word
appears in the output of file "$f"
. I use file --
to protect against files whose name begins with -
.
for f in *.doc; do
if file -- "$f" | grep -s 'Microsoft Word'; then
…
fi
done
All we need to do is add the command to move the files.
for f in *.doc; do
if file -- "$f" | grep -s 'Microsoft Word'; then
mv -- "$f" ../NewDirectory/
fi
done
If you want to look for files in subdirectories as well, use the **
wilcdard pattern for recursive globbing. In bash, it needs to be activated with shopt -s globstar
(in ksh93, you need set -o globstar
, and in zsh it works out of the box; other shells lack this feature). Beware that bash ≤4.2 follows symbolic links to directories.
for f in **/*.doc; do
if file -- "$f" | grep -s 'Microsoft Word'; then
mv -- "$f" ../NewDirectory/
fi
done
Note that all moved files end in ../NewDirectory/
, no subdirectories are created. If you want to reproduce the directory tree, you can use string manipulation constructs to extract the directory part of the file name and mkdir -p
to create the target directory if necessary.
for f in ./**/*.doc; do
if file "$f" | grep -s 'Microsoft Word'; then
d="${f%/*}"
mkdir -p ../NewDirectory/"$d"
mv "$f" ../NewDirectory/"$d"
fi
done
Rather than parse the output of file
, which is somewhat fragile, you might prefer to parse file -i
, which prints standardized strings.
Best Answer
Two options
find
. e.g.find ~/Documents -name '*finances*'
locate
(requires up to date index withupdatedb
). e.g.locate finances
to put this in a script, you can do
careful about shell gobbing, i.e. a
*
in the pattern is firstly expanded by bash to match filenames in the current directory.The multitude of options to
find
is documented:man find
.Welcome to Linux!