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.
