Я не уверен, отправить ли это на StackOverflow или AskUbuntu, на основе моего текущего понимания, что проблема заключается в моем отсутствии понимания прав и полномочий/обработки выполнения в рамках Ubuntu вместо подхода программирования Java, следовательно я думал, что это было местом для выяснения.
В то время как успешное выполнение терминальных команд генерировало в проекте Java, который компилируется в a commandUbuntu.jar
, Я нашел команду, которая не выполняется, поскольку я думал, что она будет. Я установил taskwarrior 2.5, и я пытаюсь создать пользовательский определяемый пользователем атрибут (UDA) с помощью Java. Команда (команды), is/are:
printf 'y\n' | sudo task config uda.newTestSort.type numeric
printf 'y\n' | sudo task config uda.newTestSort.label nTSort
воспроизведение Taskwarrior может быть установлено с:
sudo apt update && sudo apt upgrade
sudo apt install task
Можно добавить 2 задачи с:
task add this is the test task one description
task add test task two
Присоединенный MWE, созданный, чтобы просто выполнить 2 команды, он может быть скомпилирован в .jar
в затмении путем нажатия: file>export>select node Java>Select Runnable JAR file>Click next>Launch Configuration:
CommandLinux - LearnToSayYesToLinux>Chose an export location and name, e.g.
c:/commandLinux.jar'> Пакет потребовал, чтобы библиотеки в сгенерированный JAR> Нажали Finish.
Затем это может быть выполнено в Ubuntu с:
cd /mnt/c/commandLinux.jar
java -jar commandLinux.jar
MWE:
package learnToSayYesToLinux;
import java.io.*;
import java.util.ArrayList;
public class CommandLinux {
public static void main(String[] args) {
// TODO Auto-generated method stub
//Test create a custom UDA
createUDA("abstractSort","aSort","numeric");
System.exit(0);
}
/**
* Method creates a taskwarrior user defined Attribute if the data type is correct
* Thows error datatype is not correct.
* TODO: write proper exception
* @param udaName
* @param label
* @param type
*/
private static void createUDA(String udaName, String label,String type) {
char vd = (char)124; //vertical dash: |
char bs = (char)92; //backslash: \
String[] commands = new String[2];
//Check if the datatype is correct for taskwarrior:
if (type.equals("numeric") || type.equals("string") || type.equals("date") || type.equals("duration")){
commands[0]="printf 'y"+bs+"n' "+vd+" sudo task config uda."+udaName+".type "+type;
commands[1]="printf 'y"+bs+"n' "+vd+" sudo task config uda."+udaName+".label "+ label;
runCommands(commands[0], false);
runCommands(commands[1], false);
System.out.println("Ran:"+commands[0]);
System.out.println("Ran:"+commands[1]);
//Trow exception if the datatype is not correct.
}else {
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static ArrayList<ArrayList<String>> runCommands(String command,boolean ignoreOutput) {
String s = null;
String outputLines=null;
ArrayList<String> goodExecutionOutput=new ArrayList<String>();
ArrayList<String> errorExecutionOutput=new ArrayList<String>();
ArrayList<ArrayList<String>> returnLists = new ArrayList<ArrayList<String>>();
try {
// run the Unix "task nice0" command
Process p = Runtime.getRuntime().exec(command);
BufferedReader brGood = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader brError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
// get output
if (!ignoreOutput) {
while ((s = brGood.readLine()) != null) {
System.out.println("Adding:"+s);
goodExecutionOutput.add(s);
}
// get the error message
while ((s = brError.readLine()) != null) {
errorExecutionOutput.add(s);
}
}
}
catch (IOException e) {
System.out.println("Error: ");
e.printStackTrace();
System.exit(-1);
}
//Merge outputLists and return
returnLists.add(goodExecutionOutput);
returnLists.add(errorExecutionOutput);
return returnLists;
}
}
Результат, Если команда выполняется .jar
файл это возвращается:
$ ationAndSystems/Taskwarrior/customSortServerV4 Java - банка testCommand.jar
Adding:'y
Adding:'
Adding:'y
Adding:'
Ran:printf 'y\n' | sudo task config uda.newTestSort.type numeric
Ran:printf 'y\n' | sudo task config uda.newTestSort.label nTSort
Если я выполняю команду вручную, она возвращается:
$ printf 'y\n' | sudo task config uda.newTestSort.type numeric
Are you sure you want to change the value of 'uda.newTestSort.type' from 'numeric' to 'numeric'? (yes/no) Config file /home/a/.taskrc modified.
$ printf 'y\n' | sudo task config uda.newTestSort.label nTSort
Are you sure you want to change the value of 'uda.newTestSort.label' from 'nTSort' to 'nTSort'? (yes/no) Config file /home/a/.taskrc modified.
Интерпретация/тестирование этого результата обсуждена при "Проверке".
Попытка результата 2, Как предложено в комментариях: Изменение строк 36 и 37 из MWE к:
commands[0]="yes yes "+vd+" sudo task config uda."+udaName+".type "+type;
commands[1]="yes yes "+vd+" sudo task config uda."+udaName+".label "+ label;
Приводит к бесконечному повторению (пока Переполнение стека не происходит):
Adding:yes | sudo task config uda.testSortA.type numeric
Если я установил boolean ignoreOutput
ко лжи, когда я называю метод runCommands()
это возвращается:
Ran:yes yes | sudo task config uda.testSortA.type numeric
Ran:yes yes | sudo task config uda.testSortA.label tSortA
После проверки я пришел к заключению, что эта команда эффективно не добавила новый UDA.
Проверка, Если я вручную ввожу их в Ubuntu 16.04, они хорошо работают. Я тестирую его путем ввода:
sudo task 2 modify newTestSort:29
Если UDA еще не будет существовать в taskwarrior, то он интерпретирует тот оператор как: "измените описание задачи 2". Однако, если UDA newTestSort
действительно существует и имеет тип numeric
это установит задачу 2 uda newTestSort
(маркированный nTSort
) к 2. Эти два результата читаются в выводе команды sudo task 2
, сначала, прежде чем создание UDA для проверки UDA еще не существует путем проверки, было ли описание задачи изменено на newTestSort:29
и второй раз, после ввода 2 упомянутых выше команд создания UDA, для проверки UDA действительно создается путем проверки если новый UDA nTSort
перечислен со значением 29.
Вопрос: Как я автоматически отвечаю на "да" на подсказку ниже, не создавая дополнительный файл, с помощью Java?
Вы уверены, что хотите изменить значение 'uda.newTestSort.type' от 'числового' до 'числового'? (да/нет) Файл конфигурации/home/a/.taskrc измененный.
Текущее понимание
ответа lesmana объясняет, что вертикальный тире соединяет вход для того, что является правильным из тире с выводом того, что оставляют тире. Это говорит что вывод yes
бесконечный поток y
поэтому после того, как команда просит вход, это передало бы их потоком y
- s в тот вопрос. Я в настоящее время не понимаю, почему это прекратило бы делать это.
Другое сомнение, которое я имею, состоит в том, что команда могла бы быть интерпретирована по-другому по сравнению с тем, когда она вручную вводится из-за способа, которым она дана от a .jar
файл к процессу вместо вводимого в терминал. Это могло бы вызвать для другой интерпретации/значения |. Я изучаю, как команды интерпретируются от a .jar
файл человечностью.
Дополнительно я проверил, было ли это проблемой с правами что .jar
файл имеет, таким образом, я пытался выполнить предложенную команду попытки 2 с:
sudo java -jar commandUbuntu.jar
Но после проверки я пришел к заключению, что это не допускало добавление нового UDA от Java.
Решение сущности проблемы было отправлено Pepe ниже принятого ответа в: https://stackoverflow.com/questions/4157303/how-to-execute-cmd-commands-via-java
С моим текущим пониманием команда может иметь ввод и вывод. Вертикальный тире |
используется для передачи по каналу в терминале. Так, например, предположите, что у Вас есть команда, которая генерирует вывод, например yes
, затем тот вывод может быть связан непосредственно с входом другого command*. Предположим, что другая команда является командой, которую я пытался выполнить, который имеет вход из-за вопроса:
Вы уверены, что хотите изменить значение 'uda.newTestSort.type' от 'числового' до 'числового'? (да/нет) Файл конфигурации/home/a/.taskrc измененный.
Таким образом, когда, например:
printf 'yes\n' | task config uda.testSortC.type numeric
вводится как команда в нормальном терминале, это вывод команды yes
передается по каналу в команду: task config uda.testSortC.type numeric
, который отвечает на вопрос выше. Я в настоящее время понимаю, что тем вопросом самим является вывод той команды, но просто сообщение, которое сопровождает вход той команды. Получение входа yes
завершает выходной поток большого количества yes
и команда выполняется, как она должна с a yes
вход.
Теперь, когда можно назвать процесс в Java с:
Process p = Runtime.getRuntime().exec(command);
.exec(command)
не точно то же как ввод команды в Terminal^. Одно свойство различия - то, что передача по каналу не функционирует, если указано в команде, что Вы записали в Java с помощью вертикальной строки |
. Применять понятие передачи по каналу Вас должно явно получить вход команды и явно включить вывод другой команды в него. Это может быть сделано со следующим кодом в методе runCommands()
:
Process p;
try {
p = Runtime.getRuntime().exec(command);
new Thread(new SyncPipe(p.getErrorStream(), System.err)).start();
new Thread(new SyncPipe(p.getInputStream(), System.out)).start();
PrintWriter stdin = new PrintWriter(p.getOutputStream());
stdin.println("yes");
// write any other commands you want here
stdin.close();
int returnCode = p.waitFor();
System.out.println("Return code = " + returnCode);
} catch (IOException | InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
И путем добавления следующего класса к проекту:
class SyncPipe implements Runnable
{
public SyncPipe(InputStream istrm, OutputStream ostrm) {
istrm_ = istrm;
ostrm_ = ostrm;
}
public void run() {
try
{
final byte[] buffer = new byte[1024];
for (int length = 0; (length = istrm_.read(buffer)) != -1; )
{
ostrm_.write(buffer, 0, length);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
private final OutputStream ostrm_;
private final InputStream istrm_;
}
Где, насколько я в настоящее время понимаю, p
содержит "получение" процесса, который выполняет команду, затем класс SyncPipe
на самом деле канал. Вход процесса p
подключен к каналу с помощью a thread
и затем новая команда, которая генерирует вывод, выполняется stdin
. Так или иначе канал затем получает тот поток вывода и включает его во входной поток первой команды. Это решение сделано максимально явным, чтобы вынудить меня объяснить понятия, как таковые, оно могло бы все еще содержать ошибки, если так, комментируйте/редактируйте.
* (если та команда имеет вход. Я в настоящее время не знаю, имеют ли все команды исходные данные, или в противном случае я в настоящее время не знаю что happends если бесконечный поток вывода, например, yes
передается по каналу в команду без входа),
^I в настоящее время точно не знайте, каково различие, оно требует, чтобы у меня было более глубокое понимание того, какой happends в терминале и как обрабатываются команды и как выполняются процессы.