On a Mac, I have a directory of html files that are all document fragments. Using the TexFinderX app, I was easily able to do a find/replace and add everything at the top of the documents that I wanted (i.e. etc.) .
Now I need to find a way to add the closing tags to all of the documents (i.e. ). TexFinderX does not have a way to do this since the documents do not have anything in common at the end of the files.
Is there a Terminal command that can do this for all html files in a directory and it's subdirectories?
Thanks,
Linda
EDIT:
Well i was trying to keep it simple and avoid Bash scripting but it seems find doesnt allow for output redirection... so try this instead:
for f in ~/html/*.html; do echo "Processing $f file.." && cat ~/close.html >> $f; done
Put your closing tags in a file... well call it close.html and we'll jsut put it in your home directory /Users/youruser/close.html. Well assume your docs are in /Users/youruser/html
Open Terminal.app and do the following command:
find ~/html -type f -name "*.html" -exec cat ~/close.html >> {} \;
youll want to test that first... my find kung-fu is rusty
Related
I have following directory structure :
/home/dir1/abc.jpg
/home/dir1/abc.pdf
/home/dir1/dir2/abc.jpg
/home/dir1/dir2/abc1.jpg
/home/dir1/dir2/dir3/abc.jpg
and I want to copy jpg files from them to a new folder which will have same directory structure, for eg.:
/home/newdir1/abc.jpg
/home/newdir1/dir2/abc.jpg
/home/newdir1/dir2/abc1.jpg
/home/newdir1/dir2/dir3/abc.jpg
How to achieve it using rsync or any other software ?
Please help, Many Thanks !!
From the looks of what you've included in your question, there are a couple of things you might try.
You've specified that you want to "move" files. That means you either use the mv command, or use rsync's --remove-source-files option. For example:
mv /source1/* /source2/* /path/to/targetdir/
or
rsync -a /source1/ /source2/ /path/to/targetdir/
You've no doubt already read the part of rsync's man page that explains the difference between source dirs with and without their trailing slash. If not, read up, because it's important.
If your "thousands of source files [with] similar names" need to be matched from within your source directories, leaving some other files behind, you need to determine whether your "similar names" can be differentiated using pathname expansion or if you should use a regular expression. If the former, then adding the pathname expansion to your sources with either mv or rsync should be sufficient. If you need to use a regex, then find may be a better option:
find /source1/ /source2/ -regex ".*/file[A-F][0-9][0-9].txt" -exec mv "{}" /targetdir/ \;
If these don't solve the problem, then you'll need to supply more detail in your question.
I would try a little shell script like this:
#!/bin/sh
cd /home/dir1
JPEGS=`find . -name "*.jpg"`
tar cf - $JPEGS | (cd /home/newdir1 ; tar xf -)
This first gets the list of all your jpg files with their relative paths, then writes a tar file of them to a pipe into a subshell which changes to the new directory, and then extracts the tar from its stdin.
I thought this would be more of a one liner to be honest.
Pretty simple in notion:
using find on Mac OS X, locate files that meet a criteria, in my case:
all file and directories in a directory:
find ~/Downloads +time1000s
That finds what I need, then I run a conditional, if a dir exists, delete it, if not, create it:
mkdir -p ~/.Trash/safe-to-delte-these-old-files
This means I need to add print0 to my find as files will have spaces, and I want to move, not copy but either way, there is a source, and a destination, and I am getting stuck:
https://gist.github.com/5c0tt/5a2c1fd39ae99d6fca05
Line 27 and 26 seem to cause me issues, I am stuck.
Suggestions on everyone from line 1 to the end. I am trying to hard to do this with POSIX in mind, but i can't even get variables to work then.
It seems BSD does not work the exact same way as other shells and what arguments they accept, which is why I am trying to be more POSIX, as I was told it should run anywhere then.
Thank you.
Took a glance at your git link, a couple of remarks if I may (still a noob tbh so may be irrelevant) :
dir_to_clean="/Users/my_username/Downloads" should probably be dir_to_clean="/Users/$current_user/Downloads" unless you actually have a literal /Users/my_username/Downloads folder.
Instead of cd'ing into your users directory and since you have hardcoded the path to that directory, you could use pushd & popd instead in order to build a stack of directories.
To answer your question, to capture files with spaces in the name for removal you could use something like :
find $dir_to_clean -not -name . +time1000s -exec mv -- {} ~/.Trash/
Could be something like this :
# Initialise variables, user, source to clean, destination
user=$(whoami);
src="/Users/$user/Downloads";
dest="~/.Trash/safe_to_delete";
# Move to directory to clean, not necessary, but if you really want to
pushd $src;
# Check if the destination exists, if not, create it
if [ ! -d $dest ]; then
mkdir -p $dest;
else
echo "destination already exists";
fi
# Find all the file to move then move them
find . -not -name . +time1000s -exec mv -- {} "$dest/" \;
# Return to previous working directory
popd;
pushd the $src directory onto the stack. find all the files in the now current directory ., -not -name . in order to avoid trying to trash the . & .. folders, -- tells find to stop parsing command line options (in cas your file/folder is named i.e. -myfile.txt), exec mv all of the arguments to $dest. popd the still current directory off of the stack. man find (/exec) for more details.
Note : It is also interesting to know that the difference of execution time between the -exec option versus results being piped into xargs can and will often be quite dramatic. Also, if your are actually sure that those files are safe_to_delete, then delete them instead of moving them (-exec rm -- {} $dest/). With all that said, you were correct, one liner.
Further reading :
http://www.softpanorama.org/Tools/Find/using_exec_option_and_xargs_in_find.shtml
I have a directory with about 5,000 subdirectories in it.
Each subdirectory contains one file each.
I'd like to collect those files and put them in the same folder somewhere.
Is there a way to do that by Mac OSX terminal command? Or should I write a, say, python script to do that?
Something like,
find . -type f -exec echo mv {} /path/to/dst/dir/ \;
You'll have to tweak this according to your circumstances, of course. See man find for details. Remove the echo when you're ready to run for real (preferably after taking a backup).
I have a lot of files named the same, with a directory structure (simplified) like this:
../foo1/bar1/dir/file_1.ps
../foo1/bar2/dir/file_1.ps
../foo2/bar1/dir/file_1.ps
.... and many more
As it is extremely inefficient to view all of those ps files by going to the
respective directory, I'd like to copy all of them into another directory, but include
the name of the first two directories (which are those relevant to my purpose) in the
file name.
I have previously tried like this, but I cannot get which file is from where, as they
are all named consecutively:
#!/bin/bash -xv
cp -v --backup=numbered {} */*/dir/file* ../plots/;
Where ../plots is the folder where I copy them. However, they are now of the form file.ps.~x~ (x is a number) so I get rid of the ".ps.~*~" and leave only the ps extension with:
rename 's/\.ps.~*~//g' *;
rename 's/\~/.ps/g' *;
Then, as the ps files have hundreds of points sometimes and take a long time to open, I just transform them into jpg.
for file in * ; do convert -density 150 -quality 70 "$file" "${file/.ps/}".jpg; done;
This is not really a working bash script as I have to change the directory manually.
I guess the best way to do it is to copy the files form the beginning with the names
of the first two directories incorporated in the copied filename.
How can I do this last thing?
If you just have two levels of directories, you can use
for file in */*/*.ps
do
ln "$file" "${file//\//_}"
done
This goes over each ps file, and hard links them to the current directory with the /s replaced by _. Use cp instead of ln if you intend to edit the files but don't want to update the originals.
For arbitrary directory levels, you can use the bash specific
shopt -s globstar
for file in **/*.ps
do
ln "$file" "${file//\//_}"
done
But are you sure you need to copy them all to one directory? You might be able to open them all with yourreader */*/*.ps, which depending on your reader may let browse through them one by one while still seeing the full path.
You should run a find command and print the names first like
find . -name "file_1.ps" -print
Then iterate over each of them and do a string replacement of / to '-' or any other character like
${filename/\//-}
The general syntax is ${string/substring/replacement}. Then you can copy it to the required directory. The complete script can be written as follows. Haven't tested it (not on linux at the moment), so you might need to tweak the code if you get any syntax error ;)
for filename in `find . -name "file_1.ps" -print`
do
newFileName=${filename/\//-}
cp $filename YourNewDirectory/$newFileName
done
You will need to place the script in the same root directory or change the find command to look for the particular directory if you are placing the above script in some other directory.
References
string manipulation in bash
find man page
In editors/ides such as eclipse and textmate, there are shortcuts to quickly find a particular file in a project directory.
Is there a similar tool to do full path completion on filenames within a directory (recursively), in bash or other shell?
I have projects with alot of directories, and deep ones at that (sigh, java).
Hitting tab in the shell only cycles thru files in the immediate directory, thats not enough =/
find /root/directory/to/search -name 'filename.*'
# Directory is optional (defaults to cwd)
Standard UNIX globbing is supported. See man find for more information.
If you're using Vim, you can use:
:e **/filename.cpp
Or :tabn or any Vim command which accepts a filename.
If you're looking to do something with a list of files, you can use find combined with the bash $() construct (better than backticks since it's allowed to nest).
for example, say you're at the top level of your project directory and you want a list of all C files starting with "btree". The command:
find . -type f -name 'btree*.c'
will return a list of them. But this doesn't really help with doing something with them.
So, let's further assume you want to search all those file for the string "ERROR" or edit them all. You can execute one of:
grep ERROR $(find . -type f -name 'btree*.c')
vi $(find . -type f -name 'btree*.c')
to do this.
When I was in the UNIX world (using tcsh (sigh...)), I used to have all sorts of "find" aliases/scripts setup for searching for files. I think the default "find" syntax is a little clunky, so I used to have aliases/scripts to pipe "find . -print" into grep, which allows you to use regular expressions for searching:
# finds all .java files starting in current directory
find . -print | grep '\.java'
#finds all .java files whose name contains "Message"
find . -print | grep '.*Message.*\.java'
Of course, the above examples can be done with plain-old find, but if you have a more specific search, grep can help quite a bit. This works pretty well, unless "find . -print" has too many directories to recurse through... then it gets pretty slow. (for example, you wouldn't want to do this starting in root "/")
I use ls -R, piped to grep like this:
$ ls -R | grep -i "pattern"
where -R means recursively list all the files, and -i means case-insensitive. Finally, the patter could be something like this: "std*.h" or "^io" (anything that starts with "io" in the file name)
I use this script to quickly find files across directories in a project. I have found it works great and takes advantage of Vim's autocomplete by opening up and closing an new buffer for the search. It also smartly completes as much as possible for you so you can usually just type a character or two and open the file across any directory in your project. I started using it specifically because of a Java project and it has saved me a lot of time. You just build the cache once when you start your editing session by typing :FC (directory names). You can also just use . to get the current directory and all subdirectories. After that you just type :FF (or FS to open up a new split) and it will open up a new buffer to select the file you want. After you select the file the temp buffer closes and you are inside the requested file and can start editing. In addition, here is another link on Stack Overflow that may help.
http://content.hccfl.edu/pollock/Unix/FindCmd.htm
The linux/unix "find" command.
Yes, bash has filename completion mechanisms. I don't use them myself (too lazy to learn, and I don't find it necessary often enough to make it urgent), but the basic mechanism is to type the first few characters, and then a tab; this will extend the name as far as it can (perhaps not at all) as long as the name is unambiguous. There are a boatload of Emacs-style commands related to completion in the good ol' man page.
locate <file_pattern>
*** find will certainly work, and can target specific directories. However, this command is slower than the locate command. On a Linux OS, each morning a database is constructed that contains a list of all directory and files, and the locate command efficiently searches this database, so if you want to do a search for files that weren't created today, this would be the fastest way to accomplish such a task.