我需要获取程序的多行输出,匹配一个字符串,并返回所有匹配的前一行。
程序输出的示例:
$ jack_lsp -p
firewire_pcm:analog-1_out
properties: input,physical,terminal,
firewire_pcm:analog-2_out
properties: input,physical,terminal,
firewire_pcm:analog-1_in
properties: output,physical,terminal,
firewire_pcm:analog-2_in
properties: output,physical,terminal,
$
我需要匹配,例如“输入”,并返回所有匹配的上一行。因此,在示例中,预期输出为:
firewire_pcm:analog-1_out
firewire_pcm:analog-2_out
这是我所拥有的,但它只返回第一个匹配项:
$ jack_lsp -p | grep -B1 input | head -1
firewire_pcm:analog-1_out
$
我究竟做错了什么?
答案1
这是您正在尝试的命令:
jack_lsp -p | grep -B1 input | head -1
这样做的问题是,head -1
将返回第一行全部的通过管道传送给它的数据流。
尝试使用以下awk
命令:
jack_lsp -p | awk '/input/{print previous_line}{previous_line=$0}'
它将打印出包含字符串“input”的每一行之前的行。这是示例数据的结果:
user@host:~$ cat <<HEREDOC | awk '/input/{print previous_line}{previous_line=$0}'
firewire_pcm:analog-1_out
properties: input,physical,terminal,
firewire_pcm:analog-2_out
properties: input,physical,terminal,
firewire_pcm:analog-1_in
properties: output,physical,terminal,
firewire_pcm:analog-2_in
properties: output,physical,terminal,
HEREDOC
firewire_pcm:analog-1_out
firewire_pcm:analog-2_out
有关此awk
方法的更多信息,请参阅以下帖子:
您可以使用以下方法完成同样的事情sed
:
<!-- language: bash -->
jack_lsp -p |sed -n '/input/{x;p;d;}; x'
有关此sed
方法的更多信息,请参阅以下帖子:
在您的特定情况下,您匹配的字符串(即“输入”)看起来没有出现在前一行中,因此您也可以使用以下方法过滤掉这些行grep
,即:
jack_lsp -p | grep -B1 'input' | grep -v 'input
awk
您还可以通过补充一些 shell 脚本来获得与上述方法相同的结果grep
,尽管结果并不那么紧凑:
jack_lsp -p | (
unset previous_line;
while read line; do
if grep -q input <<< "${line}" && [[ -n "${previous_line}" ]]; then
echo "${previous_line}";
fi;
previous_line="${line}";
done
)
答案2
使用 gnu-grep(适用于所有平台并在大多数平台上默认安装)我们可以:
jack_lsp -p | grep -zPo '.*\n(?=.*input)'
在哪里
-z
表示用 null 分隔的“行”(事实上,它最终会占用整个文件)——具有多行模式-P
类似 Perl 的正则表达式方言——具有先行功能'.*\n(?=.*input)'
由包含“input”的另一行向前查找的行
答案3
为什么不简单一点,并使用ex
具有反向寻址功能的 :
printf '%s\n' 'g/input/-p' | ex file.txt
对于在管道中而不是在文件中运行它,它看起来有点棘手,但工作原理相同:
jack_lsp -p | ex -s /dev/stdin -c $'g/input/-p\nq'
答案4
这个片段:
# Utility functions: print-as-echo, print-line-with-visual-space.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
pl " Input data file $FILE:"
head $FILE
pl " Expected output:"
cat $E
pl " Results:"
rm -f f1
ed --silent $FILE > f1 <<EOF
g/input/.-1p
q
EOF
head f1
产生:
-----
Input data file data1:
firewire_pcm:analog-1_out
properties: input,physical,terminal,
firewire_pcm:analog-2_out
properties: input,physical,terminal,
firewire_pcm:analog-1_in
properties: output,physical,terminal,
firewire_pcm:analog-2_in
properties: output,physical,terminal,
-----
Expected output:
firewire_pcm:analog-1_out
firewire_pcm:analog-2_out
-----
Results:
firewire_pcm:analog-1_out
firewire_pcm:analog-2_out
ed 命令很简单:1)找到与“输入”匹配的行2)打印上一行。
在如下系统上运行:
OS, ker|rel, machine: Linux, 3.16.0-4-amd64, x86_64
Distribution : Debian 8.9 (jessie)
ed GNU Ed 1.10
最美好的祝愿...干杯,drl