shell: can I use linux-like command style `rm tmp/ -fr` in mac - macos

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.

Related

Does bash source bash completion files in /usr/local/etc/bash_completion.d by default?

I have a bunch of bash completion files in
/usr/local/etc/bash_completion.d
most of the scripts in there have something like this at the bottom of them:
complete -F _tmux tmux
the above is for tmux.
My question is - it doesn't look like bash by default sources these files?
I see some instructions online about doing something like this:
for f in '/usr/local/etc/bash_completion.d/'*; do
source "$f"
done;
do I need to do this manually or should bash be doing this out of the box?
This varies depending on your platform and/or versions of bash and bash-completion. For example:
Ubuntu
On Ubuntu 20.04 the file /etc/bash_completion does this:
. /usr/share/bash-completion/bash_completion
And in that file I find
for dir in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do
dirs+=( $dir/bash-completion/completions )
done
Which indicates that /usr/local/share/bash-completion/completions is scanned for completion scripts. Empirical experiments supports this.
MacOS/Brew
I could not find anything about bash completion in /etc or /usr/share on my MacOS 11.2.3. Which indicates that bare Darwin does not have bash completion, which makes sense since Apple have left Bash at 3.2 because of licensing. Might have for zsh, though, I didn't look.
/usr/local/etc/bash-completion.d, which you reference, is a part of the Homebrew installation under /usr/local. In there I found some completion scripts, but not the activation script. You should not have to activate those explicitly yourself.
I did find /usr/local/share/bash-completion, again from Homebrew, and it has the script bash_completion. In it are the same lines as Ubuntu, which also makes sense since Homebrew is kinda complete "GNU" but under /usr/local. But it also reference the directory /usr/local/etc/bash-completion.d. Sourcing /usr/local/share/bash-completion/bash_completion added the completion from that directory also.
But /usr/local/share/bash-completion/bash_completion is not executed by default, so you have to add that to your ~/bash_profile or ~/profile as described here. It also describes how to handle zsh and fish.
Cygwin
Cygwin is another Posix-compliant environment which has bash completion. (I haven't checked if bash completion is part of the Posix standard, though) After installing the bash-completion package there is /usr/share/bash-completion/bash_completion as Ubuntu and Homebrew has. Here there is no /etc/bash_completion and as the ~/.bashrc I had (generated long ago) did only look for this completions wasn't activated.
Summary
Many GNU-like environments support bash_completion but you might have to
install a package
ensure that it is sourced when you log in, which is not always the case by default
If it is not activated by default in your environment, you can activate it by sourcing the "root" script (in /etc, /usr/share/bash-completion or where it might be located) from your .bashrc, bash_profile or similar.
I'm guessing YMMV for all other possible platforms (other Linux distros, MSYS2 etc.) but the above might help you to figure out how to enable completion. Which is really helpful when available.

Rename directory contents in OSX terminal

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.

Bash: Is it possible to change command before execution

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.

Bash on Mac can't do **rm aFolder -rf** [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
On Linux, you can do like rm -rf aFolder/ or rm aFolder -rf
But On Mac you only can do like rm -rf aFolder/
Does anybody know what's the problem, or how to fix it?
Most Commands in Linux can do in the both way rm -rf aFolder/ or rm aFolder -rf
But on Mac you can only do in the first way.
I am wandering if you are really aware of the differences before you downvote this question. if you can try it both on Ubuntu and Mac!
I know FreeBSD/Mac and Ubuntu are different!
In Ubuntu, mostly commands can be executed like "rm aFolder -rf" rather than ALL.
I am not mean all the commands too !.
What I want is if there is a way to make "rm aFolder -rf" works in Mac OS X too,just like Ubuntu, I think it will be convenient
In Unix commands, the default has almost always been parameters first and directory/file names last. In fact, the Unix C library has two utilities: getopt and getopt_long that handle this for almost all Unix commands. I know in MS-DOS or Windows Console, the parameters could be mixed up:
C:> rd /s/q aFolder
C:> rd aFolder /s/q
That's because the command.exe shell doesn't do much in the way of file expansion. If commands do any expansion, they have to be written to do that.
Here's the problem you are talking about. Imagine if Unix commands could take parameters both ways:
$ touch -- -rf
$ mkdir aFolder
I have created a file named -rf and a folder named aFolder.
What should:
$ rm aFolder -rf
do?
Should it remove the directory aFolder? Should it remove the file -rf? Should both be removed or just one or the other?
In standard Unix, aFolder won't be removed (since you didn't specify the -rf parameters before the first non-parmameter name on the line. However, the file -rf will be removed. With the GNU version of rm, the exact opposite happens. That's very, very bad.
Mac OS X is 100% Unix, and is compliant with SUS 03. If something is allowed on GNU/Linux, but not on the Mac, it's due to the non-standard implementation of the tool in GNU. Some of the GNU implementations are nice. Others, like this one, I can do without.
Different platforms often have their own implementations of the core utils, even though they seem to be the same, they often are quite different under the hood.
If it bothers you, you still can you busybox almost anywhere: http://busybox.net
If you rely on the Linux behavior, you can install the GNU coreutils package. I thought it might be a difference in the underlying getopt() implementation, but GNU rm behaves just as you describe Linux rm even with the same libc.

How portable is mktemp(1)?

As the title suggests — can I be reasonably sure that mktemp will exist on any unix-y operating system I'm likely to encounter?
POSIX does not seem to specify mktemp(1).
It looks like most modern systems have it, but the available functionality and the semantics of the options vary between implementations (so particular invocations may not be portable):
mktemp(1) from OpenBSD — mktemp(1) originated in OpenBSD 2.1
mktemp(1) from FreeBSD
mktemp(1) from Mac OS X — almost always the same as from FreeBSD
mktemp(1) from Todd C. Miller of sudo fame
mktemp(1) from Solaris
mktemp(1) from GNU coreutils
mktemp(1) from HP/UX — this one seems particularly divergent from most of the others listed here
So if you want a portable solution you may need to stick to functionality and options that mean the same thing on all of your platforms of interest.
A mktemp function (AKA mktemp(3)) first appeared in Unix V7 so it's likely to be everywhere. However, a mktemp command (aka mktemp(1)) first appeared, I believe, on OpenBSD 2.1, so if you have to deal with truly antediluvian Unix systems you might have to worry -- unless you can distribute the very portable mktemp.org version (to fix the potential lack of this utility on some customer's antediluvian system). How likely you are to encounter antediluvian system is nigh impossible for us to guess, of course -- e.g., in HP-UX, mktemp(1) has been around for at least 8 years (even most enterprises probably have updated their Unix OS's within that time frame), in Xenix I believe it appeared in 3.0 (in 1992), etc, etc.
FYI, mktemp appears to NOT be included with Solaris 9 (released 2002/2003) - just ran across this today:
$ uname -a
SunOS dcmnapp02 5.9 Generic_122300-47 sun4u sparc SUNW,Sun-Fire-V440
$ mktemp
bash: mktemp: command not found
$ man mktemp
bash-2.05$ man mktemp
Reformatting page. Please Wait... done
Standard C Library Functions mktemp(3C)
NAME
mktemp - make a unique file name
SYNOPSIS
#include
char *mktemp(char *template);
On Solaris 9 it's in package SMCmktemp, see http://sunfreeware.com/indexsparc9.html:
uname -s
SunOS
uname -r
5.9
/usr/sbin/pkgchk -l -p /usr/local/bin/mktemp
Pathname: /usr/local/bin/mktemp
Type: regular file
Expected mode: 0555
Expected owner: bin
Expected group: bin
Expected file size (bytes): 8884
Expected sum(1) of contents: 6493
Expected last modification: Nov 05 08:48:17 2002
Referenced by the following packages:
SMCmktemp
Current status: installed

Resources