function __fish_print_hostnames -d "Print a list of known hostnames" # This function used to primarily query `getent hosts` and only read from `/etc/hosts` if # `getent` did not exist or `getent hosts` failed, based off the (documented) assumption that # the former *might* return more hosts than the latter, which has never been officially noted # to be the case. As `getent` is several times slower, involves shelling out, and is not # available on some platforms (Cygin and at least some versions of macOS, such as 10.10), that # order is now reversed and `getent hosts` is only used if the hosts file is not found at # `/etc/hosts` for portability reasons. begin test -r /etc/hosts && read -z /dev/null end | # Ignore comments, own IP addresses (127.*, 0.0[.0[.0]], ::1), non-host IPs (fe00::*, ff00::*), # and leading/trailing whitespace. Split results on whitespace to handle multiple aliases for # one IP. string replace -irf '^\s*?(?!(?:#|0\.|127\.|ff0|fe0|::1))\S+\s*(.*?)\s*$' '$1' | string split ' ' # Print nfs servers from /etc/fstab if test -r /etc/fstab string match -r '^\s*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3]:|^[a-zA-Z\.]*:' /test/file1 /home//test/file2), # and `set` will prevent "No matches for wildcard" messages eval set expanded_path $path for path in $expanded_path # Skip unusable paths. test -r "$path" -a -f "$path" or continue echo $path set new_paths $new_paths $path end end if test -n "$new_paths" _recursive $new_paths end end _recursive $ssh_config end set -l ssh_configs /etc/ssh/ssh_config (_ssh_include /etc/ssh/ssh_config) $ssh_config (_ssh_include $ssh_config) for file in $ssh_configs if test -r $file # Don't read from $file twice. We could use `while read` instead, but that is extremely # slow. read -alz -d \n contents <$file # Print hosts from system wide ssh configuration file string replace -rfi '^\s*Host\s+(\S.*?)\s*$' '$1' -- $contents | string match -v '*\**' # Also extract known_host paths. set known_hosts $known_hosts (string replace -rfi '.*KnownHostsFile\s*' '' -- $contents) end end # Avoid shelling out to `awk` more than once by reading all files and operating on their # combined contents for file in $known_hosts if test -r $file read -z <$file end end | # Ignore hosts that are hashed, commented or @-marked and strip the key # Handle multiple comma-separated hostnames sharing a key, too. # # This one regex does everything we need, finding all matches including comma-separated # values, but fish does not let us print only a capturing group without the entire match, # and we can't use `string replace` instead (because CSV then fails). # string match -ar "(?:^|,)(?![@|*!])\[?([^ ,:\]]+)\]?" # # Instead, manually piece together the regular expressions string match -v -r '^\s*[!*|@#]' | string replace -r '^\s*(\S+) .*' '$1' | string split ',' | string replace -r '\[?([^:\]]+).*' '$1' return 0 end