![从历史记录中提取唯一的单个命令](https://linux22.com/image/99374/%E4%BB%8E%E5%8E%86%E5%8F%B2%E8%AE%B0%E5%BD%95%E4%B8%AD%E6%8F%90%E5%8F%96%E5%94%AF%E4%B8%80%E7%9A%84%E5%8D%95%E4%B8%AA%E5%91%BD%E4%BB%A4.png)
我创建了一个名为 histcopy.txt 的文件,其中包含命令历史记录 ( history > histcopy.txt
)。它看起来有点像这样:
1. l
2. ls
3. cat necopy.txt
4. netstat
5. cd | ls-l ; grep -i "3" histcopy.txt | echo
我想打印出每个唯一的命令,这是我到目前为止运行的命令:
awk '{print $2}' histcopy.txt | sort|uniq`
其结果是:
l
ls
cat
netstat
cd
但在最后一行 ( 5. cd | ls-l ; grep -i "3" histcopy.txt | echo
) 中,有许多命令被它忽略,只采用第一个cd
。如何重写当前命令以便也提取它们?这样,从第 5 行开始,它还会提取:
ls-l
grep -i "3: histcopy.txt
echo
将它们作为输出列表中的单独项目。
答案1
$ cat histcopy.txt
1 l
2 ls
3 cat necopy.txt
4 netstat
5 cd | ls -l ; grep -i "3" histcopy.txt | echo
$ sed 's/^\s*\S*\s*//' histcopy.txt | tr ';|' '\n' | awk '!seen[$1]++{print $1}'
l
ls
cat
netstat
cd
grep
echo
sed 's/^\s*\S*\s*//'
删除与history
输出中的命令关联的初始空格和数字tr ';|' '\n'
将;
和替换|
为换行符。这适用于当前的问题陈述,但如果替换中有命令等则无济于事awk '!seen[$1]++{print $1}'
独特的命令
perl
单独 实现类似的逻辑
$ perl -lne 's/^\s*\S+//; (@a)= split/[;|]/; foreach (@a){($k) = /^\s*\K(\S+)/; print $k if !$seen{$k}++}' histcopy.txt
l
ls
cat
netstat
cd
grep
echo
答案2
如果你想坚持awk
:
awk 'BEGIN {RS="\n|\\||;|\\$\\("}
$1 ~ /^[0-9]+\./ {print $2; next}
{print $1}' file | sort | uniq
解释:告诉 awk 你的记录分隔符可以是换行符或“|”,或“;”,或“$(”,这样管道、替换或链接命令将被分割成记录。然后检查你的第一个字段是否是数字后跟一个点,如果是,则位于行的开头,因此打印第二个字段;否则,打印第一个字段。