I am rewriting my own implementation of ls and I have found out that it doesn't work the same on my Macbook and my Xubuntu virtual machine.
The behavior I am testing is the use of a flag after the name of a directory, for example (Desktop and ft_ls are both directories):
/bin/ls -a Desktop -r ft_ls
produces this output on my Mac
ls: -r: No such file or directory
Desktop:
. .. .DS_Store .localized
ft_ls:
. .. .git Makefile ft_ls ft_ls.a includes libft main.c srcs test
As you can see -r is considered as a file or a directory, however on my virtual machine with approximatively the same command -r is considered as an option (Bureau and ft_ls are both directories):
/bin/ls -a Bureau -r ft_ls
produces this output on Xubuntu
ft_ls:
srcs Makefile main.c libft .git .dist .. .
Bureau/:
terminator.desktop libft .. .
You can reproduce this behavior on your own system with:
/bin/ls -a "Any directory" -r "Any directory"
Am I doing something wrong or ls is different between Linux and Macos ? Thank you for your answers !
CodePudding user response:
The GNU C library version of getopt()
thinks that you should be allowed to interleave options and arguments and therefore interprets the -r
as an option, permuting the argument array to move the -r
before the actual file arguments.
The POSIX specification for getopt()
does not specify this behaviour, and many non-GNU implementations of getopt()
do not permute the argument list. Macs (and presumably BSD systems) do not automatically use GNU getopt()
— AFAIK, you'd have to install it and link with that library before linking with the system library.
On GNU systems, you can set the environment variable POSIXLY_CORRECT
to suppress the permutation of options — I normally run with this set on my work machines and have to have cover scripts for a couple of work-provided scripts that rely on POSIXLY_CORRECT
not being set — the cover scripts unset the variable and then run the official script.
Note that using --
as an option means that anything following it is not an option; the arguments after the --
option will be treated as non-option arguments by getopt()
.
For portable work, ensure that you put options before other arguments. And if you're running multiple commands that run other commands, use --
liberally.
One command sequence I use routinely is a variation on:
repeat -n 25 -i 300 -d 120 -c -- timecmd -m -- cvl
The repeat
command repeats the command after the first double-dash (--
) 25 times, with an initial delay of 300 seconds, thereafter a delay of 120 seconds, and prints out the repeat count in the identifying information. The timecmd -m
times how long the command after the second --
takes, reporting in milliseconds. The cvl
command looks at the current build log, reporting on the progress of the build and analyzing the log file for errors. It's crucial that the -m
option is not interpreted by repeat
(because it isn't a valid option to repeat
). The --
ensures that the -m
is given to timecmd
and not subsumed by repeat
. Timing the cvl
command tells me if there are delays caused by network or other problems.