I have multiple folders with similarly named files (e.g., Article(1).rtf, Article(2).rtf, etc.). I want to store them all in a single directory, but since they have exactly the same name, they are immediately overwritten. I would like to add, for example, a different number to the name of each file depending on the folder they're in, so that the names are different. E.g., Article(1)1.rtf, Article(2)1.rtf for the first folder, Article(1)2.rtf, Article(2)2.rtf for the second, etc. How would I go by it in Terminal? Thanks.
Use mv from GNU Coreutils
One way to do this is with the mv utility from GNU coreutils. You can install it via Homebrew with:
brew install coreutils
Once you have the utilities installed, you can use GNU version of mv, which Homebrew makes available as gmv to avoid conflicts with the native BSD version. The GNU version has a very handy --backup flag, which is ideal for this use case. For example:
find . -name '*rtf' \
-exec gmv --backup=numbered {} /path/to/merge/directory/ +
This will prevent clobbering of files, and results in versioned filenames like:
Article(1).rtf
Article(1).rtf~1
Article(1).rtf~2
Article(2).rtf
Article(2).rtf~1
Article(2).rtf~2
and so forth. You can then use other Homebrew-installable utilities like fdupes to deduplicate or rename to further munge the filenames to suit your purposes.
Related
I know maybe this is a ridiculous question but i have many folders and executable files in terminal, so i need colors.
This is my question;
When i export some PATH file like this;
export PATH=/opt/local/libexec/gnubin/:$progFiles/****/*****/*****/bin:$PATH
I'm losing the colors in my terminal like when i enter a command like "ls" it can't show the colors for the folders and executables etc. all of them are just white. When i close this export command line with # i can see the colors again like a magic. Any help will be appreciated.
Thank you.
This probably happens because you prepend /opt/local/libexec/gnubin to $PATH and have the coreutils port installed. The coreutils port installs copies of the usual GNU utilities, among them ls, into /opt/local/bin, but prepends them with a g for GNU.
Additionally, the coreutils port provides the unprefixed versions in /opt/local/libexec/gnubin. So when you put that first in your $PATH, typing ls will no longer use macOS' BSD ls at /bin/ls, but GNU's ls from /opt/local/libexec/gnubin/ls, which only prints colors if you call it with --colors=auto (which is easily achieved by an alias).
When you type /bin/ls, you'll likely get the output you are used to.
I want to change the command so that command line flag(options) are placed before command line arguments, as which is done automatically by GNU getopt.
Mac use BSD getopt so that function is lacked. I want to tweak the bash so that upon executing of one command, I run a script that parse the flags and arguments reorder them and execute the reordered command.
In this way, both
ls -lh /tmp
ls /tmp -lh
will work in my Mac's terminal.
You can't safely write a general purpose tool to do the job of reordering arguments on a command line unless you know what the optstring argument to the getopt() function looks like for each command. Consider:
make something -f makefile
cp something -f makefile
In the first command, you have to move both the -f and makefile to the front to canonicalize the command invocation. In the second, you must only move the -f; if you move the following file name too, you rewrite the command and destroy your data.
Of course, you also have to know what the getopt_long() argument strings look like if the command takes long-form --force or --file=makefile style arguments too.
Frankly, you'd do better to use POSIXLY_CORRECT in your environment on Linux and forget about the insidious flexibility it provides, and learn to write your options before your arguments at all times. Your code will work across all Unix-like machines better if you do that.
You could install GNU software in some directory other than /bin and /usr/bin (e.g. /usr/gnu/bin and then ensure that you place /usr/gnu/bin on your PATH ahead of the system directories. There are pre-built systems like fink, too. However, that won't help with tools from Apple that don't have analogues from GNU. And there's a 'danger' that shell scripts you write will not be portable to other Macs that don't have the same setup that you do.
Say, I want to remve a tmp/ dir in shell.
In linux (like ubuntu), I can rm tmp/ -fr or rm -fr tmp/. But in mac, I can only rm -fr tmp/.
Is there any way to config the mac shell (bash/zsh/...), so I can use the linux-like command style: rm tmp/ -fr?
Having options after operands as in rm tmp/ -fr is non-standard. IEEE Std 1003.1-2001 has in the section 12.2 Utility Syntax Guidelines:
Guideline 9:
All options should precede operands on the command line.
The implementors of the GNU utilities (as used by most Linux distributions) have chosen to add many non-standard extensions. While sometimes convenient, using these extionsions is inherently unportable. MacOS X has a userland derived from BSD, which does not have most of the non-standard GNU extensions. If you expect to be working with non-GNU systems such as BSD, Solaris or any other commercial UNIX in the future, it really pays to stick to standard syntax of utilities and not get used to any GNU extensions. It saves a lot of hassle when working with all the different UNIX operating systems out there. This is especially true and important when writing scripts. Relying on GNU syntax in scripts will make them unportable.
So instead of installing GNU coreutils on MacOS X, my advice would be to use it as an opportunity to get used to standard syntax (IEEE Std 1003.1, POSIX.2 etc.).
It depends on the commands that you use. OS X comes from the BSD family (via NeXTSTEP), and so their standard utilities mostly descend from BSD. There is a large degree of compatibility between BSD and Linux style commands, but every once in a while you run into implementation-specific things like this. If you really want to use the Linux versions of the commands, you can install the GNU coreutils package. It's available from Homebrew (recommended) and MacPorts. In general, though, it's a pain to install the GNU coreutils over the built in BSD toolchain, because of naming clashes and such.
It general it would depend on the implementation of the command you execute. However, as for rm (given you mean rm), since you used that as an example, you cannot. At least it will not do what you think.
rm -fr tmp/: will delete directory tmp/ with the options -r and -f, so recursive (here mandatory) and forced.
rm tmp/ -fr: will (attempt) to delete directory tmp/ and/or a file/directory
named -fr, but would produce an error: rm: tmp/ directory.
Note: the only other way to remove a file named -rf would be to use rm -- -rf.
I am a heavy command line user and use the find command extensively in my build system scripts. However on Mac OS X when I am not concentrating I often get output like this:
$ find -name \*.plist
find: illegal option -- n
find: illegal option -- a
find: illegal option -- m
find: illegal option -- e
find: *.plist: No such file or directory
Basically, I forgot to add the little dot:
$ find . -name \*.plist
Because BSD find requires the path and GNU find doesn't (it assumes the current directory if you don't specify one). I use Linux, Mac OS X and Cygwin often all at the same time, so it's of great benefit to me to have all my tools behave the same. I tried writing a bash find function that added "./" if I forgot, but I failed. Thanks for your help. :)
Install GNU find instead.
$ brew install findutils
$ alias find=gfind
Yay, it works!
If you can't discipline yourself to use find 'correctly', then why not install GNU find (from findutils) in a directory on your PATH ahead of the system find command.
I used to have my own private variant of cp that would copy files to the current directory if the last item in the list was not a directory. I kept that in my personal bin directory for many years - but eventually removed it because I no longer used the functionality. (My 'cp.sh' was written in 1987 and edited twice, in 1990 and 1997, as part of changes to version control system notations. I think I removed it around 1998. The primary problem with the script is that cp file1 file2 is ambiguous between copying a file over another and copying two files to the current directory.)
Consider writing your own wrapper to find:
#!/bin/sh
[ ! -d "$1" ] && set -- . "$#"
exec /usr/bin/find "$#"
The second line says "if argument 1 is not a directory, then adjust the command line arguments to include dot ahead of the rest of the command. That will be confusing if you ever type:
~/bin/find /non-existent/directory -name '*.plist' -print
because the non-existent directory isn't a directory and the script will add dot to the command line -- the sort of reason that I stopped using my private cp command.
If you must call it 'find', then you want:
alias find=/usr/bin/find\ .
in your .profile or .bash_profile or …. Substitute the real path (if not /usr/bin/find) on your Mac OSX. Enter the full path to avoid cycles (bash normally would interpret alias find=find without issues, but better be sure).
But you better not name the alias find (findl, myfind etc), because it will become a habit and trouble for you if you try it on another system.
find ./ -name "*.plist"
edit: hmm, i may have misunderstood the question! if you were crazy, how about emulating it via a shell script? i routinely keep random utility scripts in ~/.bin, and that's the first thing in my PATH. if you had a similar setup perhaps you could do something like: (untested!)
#!/bin/sh
# remapping find!
CMD=`echo $1 | cut -c 1`
if [ $CMD = '-' ]
then
# pwd search
/usr/bin/find ./ $*
else
# regular find
/usr/bin/find $*
fi
I would suggest that if you're writing scripts (which are more likely to be migrated from one system to another sometime in the future) that you should try to use the more specific form of the command, that is specifying the "." instead of relying on a default. For the same reason, I might even suggest writing sh scripts instead of relying on bash which might not be installed everywhere.
This is probably not what you want but how about: alias find="find ."
or choose a new name (findl for find local?)
You may want to run the commands found in this link: https://www.topbug.net/blog/2013/04/14/install-and-use-gnu-command-line-tools-in-mac-os-x/
It is a bit outdated, for example I found I did not have to add many commands to my path at all.
This covers your problem by having your system use the Non-BSD find utility from the findutils package, while also installing other tools you may want as well.
I know how to show and hide hidden files in the Terminal - but is there a way to hide certain files like .DS_STORE when showing hidden files? Make certain files super-hidden, so to speak?
Use chflags with the hidden option
ie: chflags hidden fileToHide to hide the file from the Finde
and chflags nohidden fileToHide to show the file
Please do keep in mind the warning in man page:
Only a limited number of utilities are chflags aware. Some of these tools include ls(1), cp(1), find(1), install(1), dump(8), and restore(8). In particular a tool which is not currently chflags aware is the pax(1) utility.
What that means is that while you won't see in the Finder or Open/Save dialog boxes, the Terminal will still see it and possibly other programs that don't respect BSD flags.
To follow up on #ibz's answer, an alias would work fine, but you may want to make a shell script that takes parameters for a little more flexibility.
#!/bin/bash
/bin/ls $# | grep -v .DS_Store
Create the above in ~/bin and name it lv, chmod 755 on it, and remember to add ~/bin to your path in your .bash_profile
export PATH=~/bin:$PATH
You can also name it ls as long as you put ~/bin first in your PATH and use the full path to /bin/ls in your script so that you don't get recursive interpretation. Whenever you want to use the real ls, then you'll need to specify the full path.
To follow up on #tvanfosson's answer, a script would work fine, but you can make it simpler by defining a function in your .bashrc. :)
function lv { ls $# | grep -v .DS_Store; }
Do something like this in your .bashrc
alias lv="ls -al | grep -v .DS_Store"
Now use lv instead of ls to see all the files (including hidden), but excluding .DS_Store.