Last active
May 7, 2026 10:15
-
-
Save asdf913/8cebfe7b8fb2c83ecd2aad1bfc1a99d2 to your computer and use it in GitHub Desktop.
Use "which" or "where" to determine if a command is valid. Also print the path of the corresponding executable of the command. Print the actual path if the path is a link
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <dependencies> | |
| <dependency> | |
| <groupId>commons-io</groupId> | |
| <artifactId>commons-io</artifactId> | |
| <version>2.22.0</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.apache.commons</groupId> | |
| <artifactId>commons-lang3</artifactId> | |
| <version>3.20.0</version> | |
| </dependency> | |
| </dependencies> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.io.File; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.nio.charset.StandardCharsets; | |
| import java.nio.file.FileSystems; | |
| import java.util.Objects; | |
| import java.util.function.Predicate; | |
| import org.apache.commons.io.IOUtils; | |
| import org.apache.commons.lang3.StringUtils; | |
| import org.apache.commons.lang3.function.FailableFunction; | |
| public class WhichOrWhere { | |
| public static void main(String[] args) throws IOException { | |
| // | |
| System.out.println(getName(getClass(FileSystems.getDefault()))); | |
| // | |
| final String command = "java"; | |
| // | |
| System.out.println(exists(command)); | |
| // | |
| final File file = getFile(command); | |
| // | |
| System.out.println(file); | |
| // | |
| System.out.println(isLink(file)); | |
| // | |
| System.out.println(getActualFile(command)); | |
| // | |
| } | |
| private static File getActualFile(final String command) throws IOException { | |
| // | |
| File file = getFile(command); | |
| // | |
| while (file != null && exists(file) && isLink(file)) { | |
| // | |
| if (!isLink(file = readlink(file))) { | |
| // | |
| break; | |
| // | |
| } // if | |
| // | |
| } // while | |
| // | |
| return file; | |
| // | |
| } | |
| private static boolean isLink(final File file) throws IOException { | |
| // | |
| if (file == null) { | |
| // | |
| return false; | |
| // | |
| } // if | |
| // | |
| if (isLinux()) { | |
| // | |
| final File readlink = testAndApply(Objects::nonNull, file, WhichOrWhere::readlink, null); | |
| // | |
| return readlink != null | |
| && !Objects.equals(readlink.getAbsolutePath(), file != null ? file.getAbsolutePath() : null); | |
| // | |
| } // if | |
| // | |
| return false; | |
| // | |
| } | |
| private static boolean isLinux() { | |
| // | |
| return Objects.equals(getName(getClass(FileSystems.getDefault())), "sun.nio.fs.LinuxFileSystem"); | |
| // | |
| } | |
| private static File readlink(final File file) throws IOException { | |
| // | |
| if (isLinux()) { | |
| // | |
| try (final InputStream is = getInputStream( | |
| start(new ProcessBuilder("readlink", file != null ? file.getAbsolutePath() : null)))) { | |
| // | |
| return testAndApply(StringUtils::isNotEmpty, | |
| StringUtils.trim(IOUtils.toString(is, StandardCharsets.UTF_8)), File::new, null); | |
| // | |
| } // try | |
| // | |
| } // if | |
| // | |
| return null; | |
| // | |
| } | |
| private static File getFile(final String command) throws IOException { | |
| // | |
| String whichOrWhere = "which"; | |
| // | |
| if (Objects.equals(getName(getClass(FileSystems.getDefault())), "sun.nio.fs.WindowsFileSystem")) { | |
| // | |
| whichOrWhere = "where"; | |
| // | |
| } // if | |
| // | |
| try (final InputStream is = getInputStream(start(new ProcessBuilder(whichOrWhere, command)))) { | |
| // | |
| return testAndApply(Objects::nonNull, StringUtils.trim(IOUtils.toString(is, StandardCharsets.UTF_8)), | |
| File::new, null); | |
| // | |
| } // try | |
| // | |
| } | |
| private static String getName(final Class<?> instance) { | |
| return instance != null ? instance.getName() : null; | |
| } | |
| private static Class<?> getClass(final Object instance) { | |
| return instance != null ? instance.getClass() : null; | |
| } | |
| private static boolean exists(final String command) throws IOException { | |
| // | |
| return exists(getFile(command)); | |
| // | |
| } | |
| private static boolean exists(final File instance) { | |
| return instance != null && instance.exists(); | |
| } | |
| private static <T, R, E extends Throwable> R testAndApply(final Predicate<T> predicate, final T value, | |
| final FailableFunction<T, R, E> functionTrue, final FailableFunction<T, R, E> functionFalse) throws E { | |
| return predicate != null && predicate.test(value) ? apply(functionTrue, value) : apply(functionFalse, value); | |
| } | |
| private static <T, R, E extends Throwable> R apply(final FailableFunction<T, R, E> instance, final T value) | |
| throws E { | |
| return instance != null ? instance.apply(value) : null; | |
| } | |
| private static InputStream getInputStream(final Process instance) { | |
| return instance != null ? instance.getInputStream() : null; | |
| } | |
| private static Process start(final ProcessBuilder instance) throws IOException { | |
| return instance != null ? instance.start() : null; | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sample output