On OS X 10.10 and 10.11 it was possible to use the softwareupdate utility to fetch a list of available software updates programmatically, and in XML/PLIST format. You could write e.g.
softwareupdate -l -f my-updates.plist
and then parse the resulting PLIST-file. On macOS 10.12, this is no longer possible. The utility gives an error message instead, stating that the "-f" option is no longer available:
$ softwareupdate -l -f my-updates.plist
softwareupdate: invalid option -- f
usage: softwareupdate <cmd> [<args> ...]
Is there any way to programmatically do something that is equivalent to softwareupdate -l -f xml-file.plist on macOS 10.12? It doesn't have to be a command line tool, Objective-C or C or Swift-solutions are welcome as well!
(I already tried --file, --xml and similar options, but nothing seems to work. It seems like Apple just dropped this feature. I could of course just parse the output of softwareupdate -l with some regular expressions, but I'd prefer a less hacky solution.)
Related
I mean I can't use it in bash, is it not available on OS X, or is it just missing on my Mac?
It's not a PATH variable issue, because I searched with find command, and there's no file named setsid on my Mac at all.
If it's missing on OS X, is there any alternative to it?
Or if it's the case that I somehow deleted it accidentally, where can I find a copy of it?
use Brew:
brew install util-linux
Yes. /usr/bin/setsid is missing on Mac OS/X.
The OS interface is available, so based on the chapter 2 man page there may be some hope for porting the Linux source to Darwin.
While macOS does not come with a setsid command, it does come with scripting languages which support calling the setsid C function, such as Perl and Python. So, if you don't want to (or for some reason can't) install a setsid command via Homebrew (or MacPorts or whatever), another option is to write your own in a scripting language. As an example, try this Perl script (which I based off this with some minor changes):
#!/usr/bin/perl -w
use strict;
use POSIX qw(setsid);
fork() && exit(0);
setsid() or die "setsid failed: $!";
exec #ARGV;
If you don't like Perl, Python's os module has a setsid function too.
A simple demo, which relies on the fact that /dev/tty is an alias of your controlling terminal if you have one, but reads/writes to it fail with an IO error if you don't:
$ bash -c 'echo I have a controlling terminal. > /dev/tty'
I have a controlling terminal.
$ ./setsid.pl bash -c 'echo I have a controlling terminal. > /dev/tty'
bash: /dev/tty: Device not configured
$
(Warning: With the release of macOS Catalina (10.15) in 2019, Apple deprecated the Perl, Python, Ruby and Tcl language runtimes shipped with macOS – they say new software should not use them, and they may be removed in a future macOS version – and Apple is not going to update their versions, which are becoming increasingly outdated. However, they are still there in Monterey, and while I haven't upgraded to Ventura yet, I haven't heard anything about their removal in that version either. One obviously shouldn't rely on them for any supported applications – if such software needs one of these runtimes, it should install its own copy of them. However, if it is just for a quick hacky script to easily test how some program behaves without a controlling terminal, using these OS-bundled runtimes is still fine.)
Under Mac OS 10.10.3, I installed gnu-sed by typing:
brew install gnu-sed --default-names
When I type it again, I get the message:
gnu-sed-4.2.2 already installed
However, even after rebooting the system and restarting Terminal, I still cannot use the GNU version of sed. For example:
echo a | sed ’s_A_X_i’
returns:
bad flag in substitution command 'i'
What should I do to get the GNU version working?
Here are the paths in my $PATH variable.
/Users/WN/-myUnix
/opt/local/bin
/opt/local/sbin
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/bin
/Applications/calibre.app/Contents/MacOS
/opt/ImageMagick/bin
/usr/texbin
I'm sorry if my question seems obvious, but I am learning shell scripting on my own and don't quite understand yet how UNIX programs are installed. Any help to use GNU compliant commands (in this case sed, but soon I'll need others as well) on my Mac without causing damage or unnecessary clutter would be greatly appreciated.
Note (2019):
The --with-default-names option is removed since January 2019, so now that option is not available anymore.
When installing, Homebrew instructs on how to adapt the path, if one wants to use sed without the g prefix.
You already have the gnu-sed installed without the --with-default-names option.
With --with-default-names option it installs sed to /usr/local/bin/
Without that option it installs gsed
So in your case what you gotta do is:
$ brew uninstall gnu-sed
$ brew install gnu-sed --with-default-names
Update path if needed...
$ echo $PATH | grep -q '/usr/local/bin'; [ $? -ne 0 ] && export PATH=/usr/local/bin:$PATH
$ echo a | sed 's_A_X_i'
or use gsed as others suggested.
When you install the GNU version of sed for Mac OS X using:
$ brew install gnu-sed
The program that you use is gsed.
So for example:
$ echo "Calimero is a little chicken" > test
$ cat test
Calimero is a little chicken
$ gsed -i "s/little/big/g" test
$ cat test
Calimero is a big chicken
Also, to compliment the use of GNU command tools on Mac OS X, there is a nice blog post here to get the tools from linux:
Install and use GNU command line tools on Mac OS/OS X
$ brew install gnu-sed
$ export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
With these two commands gnu-sed works properly
The sed that ships with OS X is in /usr/bin.
The sed that homebrew installs is in /usr/local/bin.
If you prefer to use the homebrew one, you have two options:
Option 1
Every time you want to use homebrew sed, type
/usr/local/bin/sed
or, preferably
Option 2
Move /usr/local/bin/ ahead (i.e. before) /usr/bin in your PATH in your login profile, like this
export PATH=/usr/local/bin:<other places>
If you need to use gnu-sed command with their normal names, you
can add a "gnubin" directory to your PATH from your bashrc. Just use the following command in your bash or terminal.
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
--with-default-names didn't work for me on Mac OS X 10.14.2 so I created a symlink named sed to gsed higher in the $PATH
I also created a symlink named sed.1 to the gsed.1 manpage higher in the $MANPATH so man would access the gsed manpage instead of the default sed manpage
this export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
is only valid per terminal SESSIOn as soon as you restart its GONE ( Mojave )
Since the --with-default-names option was removed in Jan. 2019, my hack solution is:
# hack to override mac tools with homebrew versions (ls, sed, etc)
for p in `find "${HOMEBREW_PREFIX}" -type d -name gnubin` ; do
export PATH="${p}:${PATH}"
done
which is a little slow (crawling the dir every login) but works without forcing me to modify my .bashrc for every gnu tool I happen to install with brew.
A slightly faster way to do what #pjz suggests is the following:
for p in $(ls -d ${HOMEBREW_PREFIX:-/usr/local}/Cellar/*/*/libexec/gnubin); do
export PATH="${p}:${PATH}"
done
Of course this assumes every GNU package in brew will always have the same level of directories to get to gnubin.
Alternatively, you can speed up find by adding the -maxdepth 4 flag before -type d to reduce how far it has to do into directories.
When running brew install gnu-sed on latest homebrew it reports at the end:
==> Caveats
GNU "sed" has been installed as "gsed".
If you need to use it as "sed", you can add a "gnubin" directory
to your PATH from your bashrc like:
PATH="/opt/homebrew/opt/gnu-sed/libexec/gnubin:$PATH"
gnu-sed installs by default as gsed. However, if you look in /opt/homebrew/opt/gnu-sed/libexec/gnubi you'll find a sed command. So following the above instructions to update the path should mean sed runs gnu-sed.
While Googling for another bash tip, I found this page on .inputrc http://ss64.com/bash/syntax-inputrc.html, which exactly fixed what I was trying to do (put a trailing / on symlinks to directories), but as I read further, I saw that there was a way to skip completed text as well. "Awesome", I said to myself, "this bugs me about twice a week". So, I put that into my .inputrc as well, but it doesn't work, or even seem to recognize what's going on. After logging out, and logging back in, this is what I'm seeing:
$ tail .inputrc
set mark-symlinked-directories on
set skip-completed-text on
$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin10.0)
Copyright (C) 2007 Free Software Foundation, Inc.
$ bind -V | grep completed
$ bind -V | grep skip
$
That is, bash doesn't seem to recognize it's there at all... Is there something wrong with the version of bash supplied in Mountain Lion? Anything blindingly obvious I've forgotten to do?
skip-completed-text is new to bash version 4.
The: skip-completed-text is only in bash4.
On my Mac:
$ bash --version
GNU bash, version 4.2.37(2)-release (i386-apple-darwin12.1.0)
If you want install some opensource utilities i recommending you using macports (www.macports.org). Installing macports will give you one command called port and with it you can install things dead simply, like:
$ port install bash
will install bash 4 for you.
Bash v4 won't make it to OSX. Might I suggest zsh, which is not GPL3.
I want to make my bash script deal with long parameters. I found getopt, but it isn't supported in OS X. Can anyone tell me why getopt was implemented by BSD, but not GNU?
I tried building getopt in GNU C lib, but it failed for my poor skills with Linux.
Did anyone do this work?
There is a brew bottle for getopt.
Just run brew install gnu-getopt.
You can either specify the path for it like
/usr/local/Cellar/gnu-getopt/1.1.6/bin/getopt
Or use brew link --force gnu-getopt so it will be linked in /usr/local/bin/
Just be aware that forcing linking might be corrupting your system (as it replaces the system getopt by the gnu one).
See maybe later answer suggesting to define FLAGS_GETOPT_CMD (though few comments state issues with it).
I recommend using Homebrew to install gnu-getopt and then adding $FLAGS_GETOPT_CMD to your ~/.bash_profile file to specify the cmd path for getopt, pointing at the homebrew location, like so:
brew install gnu-getopt
Then follow directions from brew to add to your local path:
sudo echo 'export PATH="/usr/local/opt/gnu-getopt/bin:$PATH"' >> ~/.bash_profile
Then you can add FLAGS_GETOPT_CMD:
sudo echo 'export FLAGS_GETOPT_CMD="$(brew --prefix gnu-getopt)/bin/getopt"' >> ~/.bash_profile
Open a new terminal, or run . ~/.bash_profile in existing terminal to load changes
Run echo $FLAGS_GETOPT_CMD to confirm it was actually set in your console
It's generally a better idea to use getopts instead, and stick with short options. You can see getopts in action in this StackOverflow Q&A. Short options are more standard throughout OSX command line tools, and consistency is a good thing.
Also, getopts is built in to bash, so it's definitely available in OSX, as well as every other platform that can run bash.
Note that there is a getopt is also available in OSX. From Terminal, type man getopt to see its documentation. It doesn't support long options. This is a good reason not to use long options when you're writing tools to run on OSX.
If you want to do this anyway, you can install getopt from macports. Alternately, if you want better portability, you can roll your own long argument handling.
Post some code, and we'll help debug it.
I want to list all of the applications and versions installed on my mac. Stuff like perl, php, etc., not the stuff you see in the Applications directory... Is there a unix command for that?
pkgutil --packages
or
cat /Library/Receipts/InstallHistory.plist
Not exactly a unix command but:
system_profiler -detailLevel full > myreport.txt might be a good start.
There's an option to only list software (as there is an option to ouput xml) (read the manpage for the precise syntax).
If you're using macports you could just run port installed.
You can use command for get installed apps list
Json and xml output is available.
system_profiler SPApplicationsDataType -xml
system_profiler SPApplicationsDataType -json