我有一个脚本(例如,compute.sh)在我的Ubuntu 16.04上做了一些事情并且可能以错误结束,让我们说:
[compute.sh]
#!/bin/bash
...
MISCELLANEOUS OPERATIONS
...
[if error occours]
echo "Error 55a" >&2;
exit 1;
...
echo "Execution ok";
exit 0;
和另一个处理错误的脚本(例如error_handler.sh)
[error_handler.sh]
error=$(cat)
for i in "$@"
do
case $i in
-u=*|--user=*)
username="${i#*=}"
shift
;;
-t=*|--task=*)
task="${i#*=}"
shift
;;
esac
done
...
SENDS ERROR REPORTING THROUGH AN API LISTENING REMOTELY
...
我想执行compute.sh,将其stderr重定向到error_handler.sh,以便通知我的API系统发生错误
如果我尝试这个测试:
user@ubuntu: echo "test message" | ./error_handler.sh --user=dude --task="simple task"
我的error_handler.sh脚本接受字符串"测试消息"并正确处理它
如何只将stderr输出重定向到我的error_handler.sh脚本?
编辑:因为有时compute.sh可能会在没有错误消息的情况下失败(只需执行退出1;)我不确定错误是否= $(cat)它是捕获错误的正确方法error_handler.sh中的消息。还有其他选择吗?
EDIT2:任务可以在crontab中执行,所以我需要在同一个命令中执行所有操作
答案 0 :(得分:3)
最简单的方法是创建一个命名管道作为两者之间的缓冲区。
mkfifo errors # "errors" is an arbitrary file name
compute.sh 2> errors & # Run in the background
error_handler.sh < errors
作为一行:
mkfifo errors; compute.sh 2> errors & error_handler.sh
现在两个进程同时运行,error_handler.sh
可以从errors
读取compute.sh
写入它。缓冲区的大小有限,因此如果compute.sh
已满,error_handler.sh
将自动阻止。 compute.sh
消费一些输入后,error_handler.sh
会自动恢复。只要错误不会产生得太快(即比compute.sh
处理它们的速度快),error_handler.sh
就会像缓冲区一样无限运行。
如果缓冲区被清空,compute.sh
将阻塞,直到有更多输入可用,或者直到foo | bar
通过退出关闭其管道末尾。
常规管道语法mkfifo tmp
foo > tmp &
bar < tmp
创建一个匿名管道(或未命名管道),它只是
using UnityEngine;
using System;
using System.IO;
using System.Text;
using System.Linq;
using HoloToolkit.Unity;
using System.Collections.Generic;
using UnityEngine.UI;
using Newtonsoft.Json;
#if !UNITY_EDITOR
using Windows.Networking.Sockets;
using Windows.Networking.Connectivity;
using Windows.Networking;
#endif
#if !UNITY_EDITOR
public class RootObject
{
public int Index { get; set; }
public bool Moto { get; set; }
public bool Start { get; set; }
public bool StartWINCC { get; set; }
public bool Stop { get; set; }
public bool StopWINCC { get; set; }
public bool Tag1 { get; set; }
public bool Tag2 { get; set; }
}
#endif
public class UDPCommunication : Singleton<UDPCommunication>
{
// Connection variables
public string port = "8000";
public string externalIP = "172.16.24.136";
public string externalPort = "8000";
// UI/Text elements
public Text testert;
public Image moto;
public Image start;
public Image startwincc;
public Image stop;
public Image stopwincc;
public Image tag1;
public Image tag2;
public String uitext;
// Sets up a Queue
public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();
#if !UNITY_EDITOR
// Socket initialization
DatagramSocket socket;
#endif
#if !UNITY_EDITOR
// use this for initialization
async void Start()
{
Debug.Log("Waiting for a connection...");
socket = new DatagramSocket();
socket.MessageReceived += Socket_MessageReceived;
HostName IP = null;
try
{
var icp = NetworkInformation.GetInternetConnectionProfile();
IP = Windows.Networking.Connectivity.NetworkInformation.GetHostNames()
.SingleOrDefault(
hn =>
hn.IPInformation?.NetworkAdapter != null && hn.IPInformation.NetworkAdapter.NetworkAdapterId
== icp.NetworkAdapter.NetworkAdapterId);
await socket.BindEndpointAsync(IP, port);
}
catch (Exception e)
{
Debug.Log(e.ToString());
Debug.Log(SocketError.GetStatus(e.HResult).ToString());
return;
}
var message = "hello from " + IP;
await SendMessage(message);
await SendMessage("hello");
Debug.Log("exit start");
}
private async System.Threading.Tasks.Task SendMessage(string message)
{
using (var stream = await socket.GetOutputStreamAsync(new Windows.Networking.HostName(externalIP), externalPort))
{
using (var writer = new Windows.Storage.Streams.DataWriter(stream))
{
var data = Encoding.UTF8.GetBytes(message);
writer.WriteBytes(data);
await writer.StoreAsync();
Debug.Log("Sent: " + message);
}
}
}
#else
// Use this for initialization.
void Start()
{
}
#endif
// Update is called once per frame.
void Update()
{
// Dequeues items until there are no more items on the queue.
while (ExecuteOnMainThread.Count > 0)
{
ExecuteOnMainThread.Dequeue().Invoke();
}
}
#if !UNITY_EDITOR
// this method is purely for setting the UI elements based on the received JSON string.
private void setStuff(string input){
// Turns the json string into an object
var results = JsonConvert.DeserializeObject<RootObject>(input);
// Sets the UI element(and converts it to string, because it is an int)
testert.text = results.Index.ToString();
// sets the image green if the variable is true, and red if it's not
if (results.Moto == true)
{
moto.GetComponent<Image>().color = Color.green;
}
else
{
moto.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.Start == true)
{
start.GetComponent<Image>().color = Color.green;
}
else
{
start.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.StartWINCC == true)
{
startwincc.GetComponent<Image>().color = Color.green;
}
else
{
startwincc.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.Stop == true)
{
stop.GetComponent<Image>().color = Color.green;
}
else
{
stop.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.StopWINCC == true)
{
stopwincc.GetComponent<Image>().color = Color.green;
}
else
{
stopwincc.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.Tag1 == true)
{
tag1.GetComponent<Image>().color = Color.green;
}
else
{
tag1.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.Tag2 == true)
{
tag2.GetComponent<Image>().color = Color.green;
}
else
{
tag2.GetComponent<Image>().color = Color.red;
}
}
//this method gets called when a message is received
private async void Socket_MessageReceived(Windows.Networking.Sockets.DatagramSocket sender, Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs args)
{
// Read the received message.
Stream streamIn = args.GetDataStream().AsStreamForRead();
StreamReader reader = new StreamReader(streamIn);
string message = await reader.ReadLineAsync();
Debug.Log("MESSAGE: " + message);
// if the count is zero, the message will be relayed to the setStuff method, which processes the string continuously.
// The message contains a JSON string which is received from the server.
if (ExecuteOnMainThread.Count == 0)
{
ExecuteOnMainThread.Enqueue(() =>
{
setStuff(message);
});
}
}
#endif
}
但限制您将一个命令的标准输出连接到另一个命令的标准输入。使用其他文件描述符需要扭曲重定向。使用命名管道要稍微长一些,但可以 更清楚地阅读。