sh python模块如何记录stderr / stdout并仅捕获stdout?

时间:2019-05-11 15:07:36

标签: python sh

使用sh模块,我想log进程的stdout / stderr并捕获stdout进行处理。该过程可能会花费很长时间,并且日志记录必须等到该过程完成后才能等待,以便用户实时查看输出。

以下内容可以很好地记录stdout / stderr。但是stdout与stderr混合在一起,没有方便的方法将它们彼此分开。

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<script src="//unpkg.com/office-ui-fabric-react/dist/office-ui-fabric-react.js"></script>
<div id="root"></div>

<script type="text/babel">

class SlotBookingComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      bookingDate: '',
      buttonColor: 'red',
      startTime: '',
      endTime: '',
      AvailableSlots: [],
      slots: null
    };
    this.updateState = this.updateState.bind(this);
    //this.handleSlots = this.handleSlots.bind(this);
  }

  onButtonPress() {
    this.setState({
      buttonColor: '#123eee'
    });
  }

  parseIn(date_time) {
    var d = new Date();
    d.setHours(date_time.substring(11, 13));
    d.setMinutes(date_time.substring(14, 16));

    return d;
  }

  getTimeSlots(time1, time2) {
    var arr = [];
    while (time1 < time2) {
      arr.push({
        time: time1.toTimeString().substring(0, 5),
        slots: {
          '1': false,
          '2': false,
          '3': false,
          '4': false
        }
      });
      time1.setMinutes(time1.getMinutes() + 30);
    }

    return arr;
  }

  updateState() {
    var startTime = '2019-05-06T10:30:00+05:30';
    var endTime = '2019-05-06T22:00:00+05:30';

    startTime = this.parseIn(startTime);
    endTime = this.parseIn(endTime);
    var intervals = this.getTimeSlots(startTime, endTime);
    this.setState({
      AvailableSlots: intervals
    });
  }

  componentDidMount() {
    this.updateState();
  }

  componentWillReceiveProps(props) {
    this.setState({ slots: props.SlotsData });
    console.log(this.state.slots);
  }

  handleClick(i, item, index) {
    const selected = this.state.AvailableSlots[index].slots[i.toString()];

    const slots = Object.assign({}, this.state.AvailableSlots[index].slots, {
      [i.toString()]: !selected
    });

    this.setState({
      AvailableSlots: [
        ...this.state.AvailableSlots.slice(0, index),
        Object.assign({}, this.state.AvailableSlots[index], {
          slots: slots,
          time: item.time
        }),
        ...this.state.AvailableSlots.slice(index + 1)
      ]
    });
  }

  render() {
    const AvailableSlots = this.state.AvailableSlots;

    const handleSlots = (max_slot, item, index) => {
      let slots = [];
      for (let counter = 1; counter <= max_slot; counter++) {
        slots.push(
          <div
            className="col"
            onClick={() => this.handleClick(counter, item, index)}
            style={{
              margin: 5,
              backgroundColor: item.slots[counter.toString()]
                ? 'green'
                : '#575756',
              height: '28px'
            }}
          />
        );
      }
      // console.log(slots);
      return slots;
    };

    const RowData = AvailableSlots.map(function(item, index) {
      //max_slot wold come from API
      var max_slot = 4;
      if (max_slot == 1) {
        return (
          <div className="row">
            <p>{item}</p>
            <div
              className="col"
              key={item}
              style={{ backgroundColor: '#123eee', height: '28px' }}
            >
              col
            </div>
          </div>
        );
      } else {
        return (
          <div className="data">
            <div className="row test">
              <div className="slot">{item.time}- </div>
              {handleSlots(max_slot, item, index)}
            </div>
          </div>
        );
      }
    });

    return (
      <div className="container">
        <div className="col-md-9 slot-window product-details">{RowData}</div>
      </div>
    );
  }
}

ReactDOM.render(<SlotBookingComponent />, document.getElementById("root"));

</script>

输出如下:

import sh
import logging

logger = logging.getLogger(__name__)

command = sh.bash('-c', 'echo a; echo b >&2', _iter=True, _err_to_out=True)

for line in command:
    logger.error(line)

print(command.stdout)

是否有一种方法可以做到但又不混合a b b'a\nb\n' stdout

1 个答案:

答案 0 :(得分:0)

解决方案是将_out_err设置为所需的日志记录功能(例如logging.error)。从stderrstdout中读取新行后,它将立即被调用,并向用户逐步显示输出。

但是,设置_out_err时,sh不会收集输出,因此将无法进行处理。这就是_tee=True的目的:即使设置了stdoutstderr,它也会收集_out_err

import sh
import logging

logger = logging.getLogger(__name__)

command = sh.bash('-c', 'echo a; echo b >&2',
                  _tee=True,
                  _out=lambda x: logger.error(x.strip()),
                  _err=lambda x: logger.error(x.strip()))

print(command.stdout)

输出为

a
b
b'a\n'