Ваша проблема в том, что вы перенаправляете stderr до перенаправления stdout. Это должно сработать, если вы поменяете их местами. Для иллюстрации рассмотрим следующие сценарии. foo.sh
выводит на stderr и stdout:
#!/usr/bin/env bash
## foo.sh
## Print "out" to standard output
echo out
## Print "error" to standard error
echo error >&2
bar.sh
читает ввод:
#!/usr/bin/env bash
## bar.sh
read input
## Print your input
echo "bar.sh read: $input"
И также baz.sh
:
#!/usr/bin/env bash
## baz.sh
read input
## Print your input
echo "baz.sh read: $input"
Теперь, если я запустите эти три, как вы, кажется, пытаетесь сделать, и передать их вывод в цикл while
, он работает, как ожидалось:
$ foo.sh 2> >(bar.sh) > >(baz.sh) | while read line; do echo "$line"; done
bar.sh read: error
baz.sh read: out
Однако это не удастся, если вы сделаете это наоборот:
$ foo.sh > >(bar.sh) 2> >(baz.sh) | while read line; do echo "$line"; done
bar.sh read: out
Вы можете сделать что-то вроде:
<file LC_ALL=C sort |
sed -n 'N;h;s/^\(.*\).*\n\1.*/\1/p;g;D' |
awk '{l = length}
l > max {max = l; s = $0}
END {print s}'
Мы сортируем ввод, используя сравнение байтов -и -байтов(sort
в локали C ), что гарантирует, что строки с самым длинным общим префиксом являются смежными.
sed
находит самый длинный общий префикс между одной строкой и следующей, используя обратную связь BRE -ссылки (\(.*\).*\n\1
, представляющие собой захваченную последовательность символов \(.*\)
, за которой следует любое количество символов .*
, символ новой строки \n
и та же последовательность символов, что была зафиксирована ранее \1
), которую мы печатаем.
awk
находит самый длинный из них (выбирает первый во входных данных, если их несколько, поэтому он будет первым в лексическом порядке. Используйте >=
вместо >
, чтобы получить последний ).
Обратите внимание, что он находит самый длинный общий префикс с точки зрения символов . Чтобы получить его в виде байтов , установите $LC_ALL
на C
для всех 3 команд, а не только sort
. Тогда, например, в UTF -8 локалей, вместо того, чтобы найти 2 символа St
как самый длинный общий префикс между Stéphane
и Stábat
, он найдет 3 байта,St<0xc3>
, где <0xc3>
является первой половиной символов á
и é
.
В терминах расширенного графемного кластера . Например, так что между Steps
и Stéphane
(, где é
выражается как двухсимвольный кластер графем e\u0301
), он находит St
вместо Ste
, вы можете прибегнуть кperl
:
<file LC_ALL=C sort |
perl -Mopen=locale -ne '
BEGIN{$prev = <>}
if ("$prev$_" =~ /^(\X*).*\n\1\b{g}/) {
$l = length($1);
if ($l > $max) {$max = $l; $s = $1}
}
$prev = $_;
END{print "$s\n"}'
(, где \X
соответствует расширенному кластеру графемы , а \b{g}
— границе расширенного кластера графемы (, для которой вам нужен perl 5.22.1 или новее )).
Если вы хотите найти самый длинный общий префикс всех строк во вводе (, а не только любых 2 строк во вводе ), как я изначально думал вы спрашивали, это ответили на другие вопросы и ответы здесь .