Статьи

Unix: перенаправление stderr в стандартный вывод

Я пытался оптимизировать некоторые запросы импорта Neo4j за последние пару дней, и как часть выполненного мной скрипта я хотел перенаправить вывод нескольких команд в файл для последующего анализа.

Я начал со следующего скрипта, который не делает явного перенаправления вывода:

1
2
3
#!/bin/sh
  
./neo4j-community-2.2.3/bin/neo4j start

Теперь давайте запустим этот скрипт и перенаправим вывод в файл:

1
2
3
4
5
6
7
$ ./foo.sh > /tmp/output.txt
Unable to find any JVMs matching version "1.7".
  
$ cat /tmp/output.txt
Starting Neo4j Server...WARNING: not changing user
process [48230]... waiting for server to be ready.... OK.
http://localhost:7474/ is ready.

Таким образом, строка о том, что не найдено подходящей JVM, выводится в stderr. Это довольно легко исправить:

1
2
3
#!/bin/sh
  
./neo4j-community-2.2.3/bin/neo4j start 2>&1

Давайте снова запустим скрипт:

1
2
3
4
5
6
7
$ ./foo.sh > /tmp/output.txt
  
$ cat /tmp/output.txt
Unable to find any JVMs matching version "1.7".
Starting Neo4j Server...WARNING: not changing user
process [47989]... waiting for server to be ready.... OK.
http://localhost:7474/ is ready.

Отлично, это сработало, как и ожидалось. Затем я расширил скрипт, чтобы остановить Neo4j, удалить все его данные, запустить его снова и выполнить скрипт cypher:

1
2
3
4
5
6
#!/bin/sh
  
./neo4j-community-2.2.3/bin/neo4j start 2>&1
rm -rf neo4j-community-2.2.3/data/graph.db/
./neo4j-community-2.2.3/bin/neo4j start 2>&1
time ./neo4j-community-2.2.3/bin/neo4j-shell --file foo.cql 2>&1

Давайте запустим этот скрипт и перенаправим вывод:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
$ ./foo.sh > /tmp/output.txt
Unable to find any JVMs matching version "1.7".
  
real    0m0.604s
user    0m0.334s
sys 0m0.054s
  
$ cat /tmp/output.txt
Unable to find any JVMs matching version "1.7".
Another server-process is running with [50614], cannot start a new one. Exiting.
Unable to find any JVMs matching version "1.7".
Another server-process is running with [50614], cannot start a new one. Exiting.
+---------+
| "hello" |
+---------+
| "hello" |
+---------+
1 row
4 ms

Похоже, перенаправление нашего stderr -> stdout на последней строке не сработало. Насколько я понимаю, команда ‘time’ поглощает все последующие аргументы, тогда как мы хотим, чтобы перенаправление выполнялось впоследствии.

Мы можем обойти эту проблему, поместив фактическую команду в блок кода и перенаправив вывод этого:

1
2
3
4
5
6
#!/bin/sh
  
./neo4j-community-2.2.3/bin/neo4j start 2>&1
rm -rf neo4j-community-2.2.3/data/graph.db/
./neo4j-community-2.2.3/bin/neo4j start 2>&1
{ time ./neo4j-community-2.2.3/bin/neo4j-shell --file foo.cql; } 2>&1
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
$ ./foo.sh  > /tmp/output.txt
  
$ cat /tmp/output.txt
Unable to find any JVMs matching version "1.7".
Another server-process is running with [50614], cannot start a new one. Exiting.
Unable to find any JVMs matching version "1.7".
Another server-process is running with [50614], cannot start a new one. Exiting.
Unable to find any JVMs matching version "1.7".
+---------+
| "hello" |
+---------+
| "hello" |
+---------+
1 row
4 ms
  
real    0m0.615s
user    0m0.316s
sys 0m0.050s

Намного лучше!