What does cd’s `-#` option do? - macos

So, if I man cd, I get the manpage for bash builtins.
If I cd -?, I get the following:
cd -?
-bash: cd: -?: invalid option
cd: usage: cd [-L|[-P [-e]] [-#]] [dir]
I know what the first two options are. Then I searched for both options.
For the -e option, I found this answer on the Unix StackExchange.
For the -# option, I couldn’t find any explanation.
My system info:
OS X 10.9 (Mavericks)
bash 4.3.18 (installed with the Homebrew package manager for OS X)
However, if I run which cd, I get /usr/bin/cd. Homebrew doesn’t touch anything outside of /usr/local, so I can only assume this is the system’s cd.
But I can’t find the documentation for that option! It’s driving me crazy.
Does anyone know what -# does?

It's a new option (as of bash-4.3). The changelog contains the following description:
'cd' has a new `-#' option to browse a file's extended attributes on
systems that support O_XATTR.
(changelog)
Type help <name> or man bash to get more info on bash commands. (In the bash man page you can search for cd by typing / followed by a search string and enter. n to go to the next hit, shift+n to go backwards).
The bash man page contains the following:
On systems that support it, the -# option presents the extended
attributes associated with a file as a directory.

Check the man page for bash for an explanation. The relevant portion says:
If dir begins with a slash (/), then CDPATH is not used. The -P option causes cd to use the physical directory structure by resolving symbolic links while traversing dir and before processing instances of .. in dir (see also the -P option to the set builtin command); the -L option forces symbolic links to be followed by resolving the link after processing instances of .. in dir. If .. appears in dir, it is processed by removing the immediately previous pathname component from dir, back to a slash or the beginning of dir. If the -e option is supplied with -P, and the current working directory cannot be successfully determined after a successful directory change, cd will return an unsuccessful status. On systems that support it, the -# option presents the extended attributes associated with a file as a directory. An argument of - is converted to $OLDPWD before the directory change is attempted. If a non-empty directory name from CDPATH is used, or if - is the first argument, and the directory change is successful, the absolute pathname of the new working directory is written to the standard output.

Related

How does "which" work in osx?

I'm trying to install a linter for sublime tex in OSX. It cannot be found in sublime. According to the docs, this is likely because the PATH is wrong. It says I should try this:
hash -r
which linter
but replace linter with the "linter executable". I tried
which standard
which sublimeLinter-contrib-standard
which fooBarBaz
but neither of them returns anything. Do I need to execute this in a particluar directory or is something else wrong?
which uses the value of PATH that it inherits. The fact that which returns nothing confirms that you need to add the appropriate directory to your PATH.
which command looks through the directories defined in your shell’s PATH variable, as well as any aliases you have defined in your ~/.bash_profile file, to find the location of the command given as an argument. This is useful when you want to find out exactly which version of a command is being used. Here’s an example:
$ which ls
/bin/ls
This tells you that when you use the ls command, it is /bin/ls that is run. This command will also tell you if a specific command is a shell builtin.

Mac terminal error -bash: command not found - El Capitan 10.11.13

I'm getting an error message when I first open my Mac terminal -
-bash: Applications: command not found
Oddly (or maybe not so oddly), when I open another tab, I sometimes get a different error -
-bash: README.md: command not found
or
-bash: [: missing `]'
I just noticed that this morning... there are two things that I did last night that I feel may have led to this, but I'm not sure if I am correct, nor do I know how to appropriately fix this issue. My OS is El Capitan 10.11.13.
First off, last night, I used Homebrew to install PostGIS 2.2 - my Postgres version is 9.5.1.
Second, I made a Github pull request for one of my projects (I'm not sure how a pull request could upset my bash profile, but Github's standard readme format is README.md, so I thought I'd better mention this here).
My bash profile seems clean to me -
[[ -s "$HOME/.profile" ]] && source "$HOME/.profile" # Load the default .profile
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function
export PATH=${PATH}:/usr/local/mysql/bin
* #EDITED TO INCLUDE THIS ASTERISK, WHICH I NEGLECTED BEFORE
Can anyone shed some light on what happened and how I can go about fixing this? I'm fairly new to using the terminal, so I'm not quite sure how to interpret this.
How to troubleshoot Bash startup problems:
To build on Jonathan Leffler's helpful comment:
From an existing terminal window, run script log.txt bash -lxv
This will create a new login (-l) shell (which is the type of shell Terminal.app on OSX creates by default) and log all its startup activities.
In addition to capturing regular output,
-v shows unexpanded source lines as they're being read.
-x shows the expanded, individual commands that are executed, prefixed with +.
Execute exit to terminate that shell, which will save everything that was just printed to log.txt.
Study file log.txt to see what's going on.
What turned out to be the OP's problem:
A stray * on a single line in their profile expanded to an alphabetically sorted list of the names of the files and folders in the then-current directory (a process called pathname expansion or globbing).
Not only is a * as its own command (or the start of a command) not useful, it could result in unwanted execution of a command (see below).
Bash then tried to execute the result of this expansion as a command to execute, with the 1st word (whitespace-separated token) interpreted as the command name.
This failed, because that first word happened not be a command name.
However, if the first word happened to be a valid command name such as file, that command would execute.
(Unless the current dir. happens to be in the $PATH, it doesn't matter whether the first matching filename is an executable file or not - all that matters is whether the name matches an existing command name).
On startup, the user's home dir. was the working dir.; by contrast, opening another tab later uses the then-current working dir., whatever it happens to be.
This explains the differing symptoms, as globbing in different directories will typically result in different name lists, the respective first word of which Bash will try to execute.
Thanks to everyone's help here, I was able to resolve this issue. When I posted my question, I left a tiny but important detail out of my bash profile - a lone asterisk on the last line.
[[ -s "$HOME/.profile" ]] && source "$HOME/.profile" # Load the default .profile
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function
export PATH=${PATH}:/usr/local/mysql/bin #ADDS MYSQL TO PATH EVERY TIME TERMINAL OPENS
*
I didn't even notice this thing before, let alone understand that it was doing anything. I commented it out and now everything runs perfectly. I'm not sure if this asterisk is a standard part of the bash profile or not, but if it has been there all along, it didn't cause me any trouble until this morning, after I had installed PostGIS and made a Github pull request. I'm not sure why those actions would have triggered this problem, but I'm trying to be as descriptive as possible in case anyone else runs into this.

How to install custom man (manual) pages on mac os x

I am trying to install a man page for a bash script on Mac OS X 10.9.5. The procedure that I tried to follow is summarised here: man page tutorial. I also summarise the steps that I tried below:
cp custom_command.1 /usr/local/man/man1/custom_command.1
gzip /usr/local/man/man1/custom_command.1
When trying man custom_command I receive the output No manual entry for custom_command. I also tried other installation methods mentioned in man page tutorial.
It is interesting to note that the steps above worked for the emacs console, i.e. I do get the correct manual when I type man custom_command. However, the command is not recognised by the autocomplete and I receive the following warning before I am able to read the manual: WARNING: terminal is not fully functional.
Any advice on how to resolve the issues above (i.e. both with the system terminal and the emacs console) would be appreciated.
Remark 1
For a reference, the man script that I am trying to install was taken from the tutorial and is restated below for a reference:
.\" Manpage for nuseradd.
.\" Contact vivek#nixcraft.net.in to correct errors or typos.
.TH man 8 "06 May 2010" "1.0" "nuseradd man page"
.SH NAME
nuseradd \- create a new LDAP user
.SH SYNOPSIS
nuseradd [USERNAME]
.SH DESCRIPTION
nuseradd is high level shell program for adding users to LDAP server. On Debian, administrators should usually use nuseradd.debian(8) instead.
.SH OPTIONS
The nuseradd does not take any options. However, you can supply username.
.SH SEE ALSO
useradd(8), passwd(5), nuseradd.debian(8)
.SH BUGS
No known bugs.
.SH AUTHOR
Vivek Gite (vivek#nixcraft.net.in)
First of all you may want to check if the man page your are trying to install is properly formatted and can be opened by man command. To do this pass the path to the man file to man command. It must contain a slash in order to be recognized as a path, for example:
man /usr/local/man/man1/custom_command.1
Then you should make sure the path you are installing your man page to is on the search list of man command. In order to find the man page its path must be either:
specified with -M option to the man command
set in the environmental variable MANPATH
listed in its config file (/private/etc/man.conf on OS X) under MANPATH statement or under MANPATH_MAP statement (which applies only to locations in your PATH environmental variable)
located in the location relative to where binary is installed, i.e.: if binary is installed in path/bin the man page is searched for in path/man, path/cat and path/bin/man, path/bin/cat
listed in files added in /private/etc/manpaths.d/ directory
The name of the man page file must be same as command name with optional section number. It may be gzipped.
To see where man will search for your custom_command man page run
man -d custom_command
OS X user command man pages are typically created in:
/usr/local/share/man/man1
If you prefer to create man pages in a different directory edit:
/private/etc/man.conf
Then add the new path to MANPATH_MAP, for example:
MANPATH_MAP /usr/local/bin /usr/local/man
To have man search a non-default path with a default fallback (/usr/local/share/man):
MANPATH /usr/local/man
MANPATH /usr/local/share/man
MANPATH_MAP /usr/local/bin /usr/local/share/man
Manual pages in MacOS X
The man command in MacOS X uses a sophisticated method of finding manual page files, based on the invocation options and environment variables, the /private/etc/man.conf configuration file, and some built in conventions and heuristics.
In MacOS X you have a command:
/usr/bin/manpath
That lists all your current locations for searching for man pages.
It can be invoked by just typing
manpath
in a Terminal.
It does not however add this to your $MANPATH shell variable.
But you'll still have access to the manpages with the man command.
What get's included in manpath is defined in
/private/etc/man.conf
It's not advised to export an environment variable called MANPATH without adding the output of:
`manpath`
to the list.
So if you want to export $MANPATH to your shell environment, do it like:
export MANPATH="`manpath`:/path/to/man/pages/to/include"
That way you'll get a complete list of manpages defined by the OS and any paths you add yourself.
For more info, open up a terminal and check:
man manpath
and the man.conf file with:
more /private/etc/man.conf
Usually a better option for including man pages in peculiar places, is to create a symlink to the directory containing the man pages in /usr/local/share/man which is indexed by the "man ecosystem" by default.
I had installed packages via brew, but the man command was drawing a blank because I had installed brew to a different directory.
To get round this, still linking the packages (which linked content up a few directories), I could then add to MANPATH in my .bash_profile, like so...
MANPATH="/Users/me/Developer/share/man:$MANPATH"
While existing answers do provide some hints/options which can help solve the OP's problem, they do not actually answer the question in title.
Indeed, in order for the man program to open the man page, it should know where to look for it. This is an obvious statement, but it doesn't help much. The question is whether you should use some "standard" location (and if so, what are those "standard" lookup paths, and where are they defined), or should you place the man page along with your program, and somehow point the man program to your custom location?
The OP seems to have tried placing the man page to what he thought was a "standard" location (/usr/local/man), but the man was unaware of it.
It should have worked if, instead of /usr/local/man/man1/custom_command.1, a /usr/local/share/man/man1/custom_command.1 was used. How could you know this? The answer is in the /etc/man.conf:
#
# Every automatically generated MANPATH includes these fields
#
MANPATH /usr/share/man
MANPATH /usr/local/share/man
MANPATH /usr/X11/man
MANPATH /Library/Apple/usr/share/man
/etc/man.conf is used to configure the default manpath (the provided example is from the default man.conf in macOS Big Sur). That being said, I don't think relying on man.conf default configuration and simply copying the man page for your custom program/script to one of these directories is the right thing to do.
The reason is that the default manpath is configured according to the man.conf only if the $MANPATH environment variable is not set or is empty. If the $MANPATH environment variable is set/not empty, the paths in the /etc/man.conf are not used to look up the man pages.
By default, $MANPATH is not set. But if your program/script + man page will be distributed to other users, you can't be sure whether or not it's set there.
So, what would be a reliable solution? In my opinion, shipping the man pages along with the script, and using the path_helper (man path_helper for more info) to point man to the custom manpath is the best way to go for third-party programs.
From the program/script author the only thing that's needed is to place the file, containing the path to the program man pages, into the /etc/manpaths.d directory. path_helper should do the rest.
It seems that path_helper was designed specifically for such use case, and it's being used by third-party programs (I learned about it after installing Wireshark and while trying to make its man pages discoverable), but there is one caveat:
path_helper will not make the man aware about your custom manpath, if the $MANPATH environment variable was not previously set (and as we know, it's not set by default). From path_helper man page:
(The MANPATH environment variable will not be modified unless it is already set in the environment.)
And this is the reason why you would actually want to set the $MANPATH, to allow the path_helper to augment it with custom manpaths afterwards.
In my case I added export MANPATH (just to set it, without any value) to /etc/zshenv (I am using macOS Big Sur, zsh is the default shell), and path_helper successfully added all the custom manpaths from /etc/manpaths.d files.
Besides all the entries pointed out in baf's answer, there's also /etc/manpaths, which is quite convenient to use for including man pages installed via Homebrew.
For example, below is the content of my /etc/manpaths:
/usr/local/opt/coreutils/libexec/gnuman
/usr/local/opt/findutils/libexec/gnuman
/usr/local/opt/gawk/libexec/gnuman
/usr/local/opt/gnu-sed/share/man
/usr/local/opt/readline/share/man
/usr/local/share/man
/usr/share/man
Meanwhile make sure in /etc/profile, MANPATH is defined before path_helper is loaded:
export MANPATH= # hack: path_helper doesn't setup MANPATH without this
eval `/usr/libexec/path_helper -s`
BTW, in macOS, the default pager is /usr/bin/less is a bit old, and doesn't even support \b for word boundary in regex, so you might want to setup MANPAGER in ~/.bashrc (or somewhere you prefer):
export MANPAGER=/usr/local/bin/less

How can I debug $PATH?

There is a directory in my $PATH that I want removed.
But I cannot figure out how it got there.
I've looked at all the places I can think of where $PATH gets set: .profile, .bashrc, .bash_profile, et cetra
but I cannot find who is putting this particular directory into $PATH.
Clearly, I do not know all the things that change $PATH when my system starts.
Is there a way to debug the startup sequence?
Ideally I just want to set a trap on anything that touches $PATH.
Or may there is a log file (or ordered set of log files) I can scan.
How can I find how each directory gets set in $PATH among all the things that run when my system starts?
There are two ways to do this:
Try bash --login -x in a terminal window. This will print every line of the setup scripts as they are executed (kudos go to kojiro).
Alternatively, you could add set -x near the top of /etc/profile or $HOME/.profile. The danger here is that if you make a mistake, your system may become unusable (if you can't start a new shell anymore) plus you need to be root. If you want to try this, I suggest to create two terminal windows, keep them open at all cost, make the changes and then start new terminal windows to see the effects.
Use grep -r PATTERN / (replace PATTERN with the path that you look for). That should search your whole hard disk for this pattern and can take a long time. Maybe start with your home directory. If you want to search just the . files, use this trick: grep -r PATTERN .??*
If you are using BASH, the way the login loading works is this order:
/etc/profile is first read in.
$HOME/.bash_profile is read in.
If $HOME/.bash_profile doesn't exist, then $HOME/.bash_login is read in.
If $HOME/.bash_login doesn't exist, then $HOME/.profile is read in.
NOTE: That $HOME/.bashrc is not read in by default. However, many people do source in their .bashrc file at login.
When a shell is invoked, and it's not a login shell, then the $HOME/.bashrc file is loaded.
By default, the Mac's PATH is /bin:/usr/bin:/usr/sbin:/sbin. This is set via /etc/profile which executes /usr/libexec/path_helper. This takes the initial paths from /etc/paths.d/... and from /etc/paths. The /etc/paths.d only adds in the /opt/X11/bin directory if X11 is installed. Otherwise, /etc/paths is used and it contains the default paths.
Mine is set to:
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
I use /usr/local/bin for third party tools. or newer versions of already installed tools. For example, /usr/bin/svn is version 1.7.17 while /usr/local/bin/svn is set to version 1.8.10. Me invoking svn will invoke the version of Subversion I installed, and not the native version.
In this case, the 1.8 version of Subversion is actually installed in /opt/subversion/bin/svn, but I create a symbolic link to it in /usr/local/svn. I do this for any tool that I install: The tool gets installed in /opt and I link the binaries and scripts to /usr/local/bin, so they're in my $PATH.
Place these 2 lines at top of your ~/.bash_profile (create it if it doesn't exist):
set -o functrace
trap '[[ "$BASH_COMMAND" == *" PATH="* ]] && echo "$BASH_COMMAND"' DEBUG
Then exit the current shell and start a new shell.
It will print every time PATH variable is set in your environment.

How can I make the "find" Command on OS X default to the current directory?

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.

Resources