2016-11-03 2 views
0

Я хочу проверить, содержит ли каталог какие-либо неработающие ссылки и возвращает номер. Я хочу использовать команду find -L /dir/* -type d -prune -o -type l | wc -l, и она отлично работает в моем терминале. Но когда я запускаю его в моем коде Java с помощью runtime.exec, он выдает ошибку:Как называть bash cmd "find -L" внутри Java-кода

Unable to call process "find -L /dir/* -type d -prune -o -type l | wc -l ". Cause: find: paths must precede expression: |Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]

Я попытался '/dar/*', "/dir/*" и /dir/\*, но ни один из них не работает. Любая помощь приветствуется.

+0

@andlrc найти: неизвестный предикат ' -L ' – user2038560

+0

Зачем вам использовать внешнюю команду для выполнения чего-то простого кода Java? – VGR

+0

@VGR Это старый проект, и он уже использовал много внешней команды. Я хочу, чтобы код был согласован. Но если я не смогу найти решение, я переключусь на простое решение Java. – user2038560

ответ

0

Оператор труб (|) - это функциональность, предоставляемая оболочкой, например, bash, а не командой find. Runtime.exec просто передает все аргументы команде, определяемой первым словом строки, - в этом случае find - и команда find не знает, что это за символ трубы.

Вы можете увидеть этот эффект для себя, выполнив команду в обычном окне терминала, но с | экранированы, как \| так передается команде find, как код Java делает:

find -L /dir/* -type d -prune -o -type l \| wc -l 

Одно общее решение передать всю команду в качестве аргумента O bash -c:

Process process = new ProcessBuilder("bash", "-c", 
    "find -L /dir/* -type d -prune -o -type l | wc -l").start(); 

(Runtime.exec является устаревшим, его замена ProcessBuilder, которая имеет больше кл . В начале определяется поведение)

Лучшее решение для подсчета строк в Java, и избежать символ трубы вообще:

Process process = new ProcessBuilder(
    "find", "-L", "/dir/*", "-type", "d", "-prune", "-o", "-type", "l").start(); 

long brokenLinkCount; 
try (BufferedReader lineReader = 
    new BufferedReader(new InputStreamReader(process.getInputStream()))) { 

    brokenLinkCount = lineReader.lines().count(); 
} 

Проходя каждый аргумент индивидуально ProcessBuilder также имеет преимущество, что команда будет работать на все пути, даже те с пробелами или кавычками в имени файла.

Наконец, даже если вы сказали, что вы не хотите идти по этому пути, лучший подход избавиться от внешних команд и сделать это в Java:

Path dir = Paths.get("/dir"); 

Stream<Path> brokenLinks = 
    Files.find(dir, 1, (path, attr) -> attr.isSymbolicLink()) 
    .filter(path -> { 
     try { 
      return !Files.exists(Files.readSymbolicLink(path)); 
     } catch (IOException e) { 
      System.err.println("Couldn't read link " + path + ": " + e); 
      return false; 
     } 
    }); 
long brokenLinkCount = brokenLinks.count(); 
Смежные вопросы