我有一个这样的txt文件。有成对的线email-password
和email-hash
。
EMAIL:[email protected]
PASSWORD:pass1
EMAIL:[email protected]
PASSWORD:pass2
EMAIL:[email protected]
PASSWORD:pass3
EMAIL:[email protected]
HASH:qwerty123
EMAIL:[email protected]
HASH:somehash
EMAIL:[email protected]
PASSWORD:pass6
我尝试仅提取email-password
不包含email-hash
行的行。在我的情况下该命令无法正常工作sed -e 's/.*EMAIL://' -e 's/.*PASSWORD://' -e "/\b\HASH\b/d" test.txt
期望输出:
[email protected]
pass1
[email protected]
pass2
[email protected]
pass3
[email protected]
pass6
答案1
sed -n 'N;s/^EMAIL://;s/PASSWORD://p' file
N
将下一行追加到模式空间,s/^EMAIL://
不用任何东西代替EMAIL:
,s/PASSWORD://p
没有任何东西替代PASSWORD:
并且仅在替换成功时打印。
在样本输入上进行测试。假设:第一行是EMAIL:
,第二行是PASSWORD:
or HASH:
,然后重复。
作为奖励,如果可能有空行,最好使用 awk,
awk -F ':' '/^PASSWORD:/{print line;print $2}/^EMAIL:/{line=$2}' file
答案2
项目管理识别 如您所知 sed 是一个面向行的流编辑器,因此当打印或不打印的决定取决于另一行(就像您的情况一样)时,我们需要编排一个状态机,在这种情况下它们将需要触发器或变量。
本质上,我们需要暂停打印,直到看到正确的状态转换。就像在本例中一样,当我们仅从状态(电子邮件行)->状态(密码行)转换时。
GNU sed
在扩展正则表达式模式下使用-E
,这使得阅读 sed 代码更容易,并且编写它时不易出现反斜杠。
$ sed -Ee '
/^PASSWORD:/!{h;d;}
x;G;s/(^|\n)[^:]*:/\1/g
' test.txt
基本思想是将不是密码行的行保存在保持寄存器中,以便当我们实际到达密码行时我们可以使用它。
使用GNU awk
我们基本上在 awk 中编写上述 sed 功能,并使用 awk 变量 e 作为保持寄存器。
$ awk -F: '
/^PASSWORD:/&&
($0=e RS $2)"";{e=$2}
' test.txt
使用GNU grep
before 选项-B
在密码行之前列出一行,然后删除 grep 生成的虚线并假设没有人使用它作为密码。
$ < test.txt \
grep -B1 '^PASSWORD:' |
grep -Fxve -- | cut -d: -f2-
perl
当我们选择下一行然后进行检查时可以如图所示使用。
$ perl -ne '
/^EMAIL:/ && ($_ .= <>);
/\nPASSWORD:/ && print(s/^[^:]+://mgr);
' tes.txt
bash 内置函数
while IFS=: read -r a p; do
case $a in
'PASSWORD') printf '%s\n' "$e" "$p" ;;
*) e=$p ;;
esac
done < test.txt
答案3
这是另外几个变体:
paste -d : - - < myfile | awk -F: '$3 == "PASSWORD" {print $2; print $4}'
tac myfile | awk -F: '$1 == "PASSWORD" {print $2; getline; print $2}' | tac
答案4
如果该文件始终采用该格式,并EMAIL
在每隔一行的开头:
sed -n 'N;s/^EMAIL:\(.*\n\)PASSWORD:/\1/p'
应该这样做。或者,为了安全起见,请查找EMAIL:
记录的开头:
sed -n '/^EMAIL:/{N;s/^EMAIL:\(.*\n\)PASSWORD:/\1/p;}'
您还可以使用pcregrep
其多行模式:
pcregrep -M -o1 -o2 --om-separator=$'\n' '^EMAIL:(.*)\nPASSWORD:(.*)'