在 Linux 上查找我最常用的命令
我是自动化的支持者,所以当我发现自己一遍又一遍地运行相同的命令时,我总是寻找一种将其包装在别名或脚本中的方法。
我在命令行上花了很多日常工作,今天我意识到我必须第100万次输入“gitstatus”,并想知道我最常用的命令是什么。所以我找到了一个堆栈溢出帖子,在一个漂亮的小bashoneliner中显示了我最常用的命令。
history|awk'{CMD[$2]++;count++;}END{for(ainCMD)printCMD[a]""CMD[a]/count*100"%"a;}'|grep-v"./"|column-c3-s""-t|sort-nr|nl| head-n10
此命令从bash历史记录中提取信息并向我显示我运行的根命令。这在我当前的系统上向我展示了以下内容。
1 6865 68.3901% git 2 761 7.58119% cd 3 441 4.39331% ll 4 425 4.23391% vagrant 5 275 2.73959% composer 6 149 1.48436% ssh 7 146 1.45447% exit 8 128 1.27515% rm 9 73 0.727237% sudo 10 72 0.717274% mv
看起来我在运行的近70%的命令中都使用了git。如果没有看到我实际运行的git命令,这很有趣但毫无意义。我决定深入研究这些数据,找出我运行最多的命令,也许是按照特定的顺序,试图尝试自动化一些步骤。
为了查看我最近运行的实际命令,我创建了一个小的PHP脚本,它将历史命令作为输入并查找最常用的运行命令。由于history命令的输出有以数字开头的行,因此需要首先从每一行中删除这些行。之后,只是构建一个命令数组作为索引数组的键,然后计算该命令在历史记录中出现的次数。
$stdin = fopen('php://stdin', 'r'); $commands = []; while (false !== ($line = fgets($stdin))) { if (strlen($line) > 300) { //防止计算长命令。 continue; } $command = preg_replace('/(\d+\*?\s{1,2})/', '', trim($line)); if (!isset($commands[$command])) { $commands[$command] = 1; } else { $commands[$command]++; } } arsort($commands); print_r(array_slice($commands, 0, 25));
为了运行它,我只是将history命令的输出通过管道传输到脚本中。使用php://stdin运行该命令的输出如下。
$ history | php history-report.php Array ( [git status] => 1527 [ll] => 468 [cd ..] => 314 [git log] => 250 [exit] => 158 [vagrant up] => 140 [cd vm] => 137 [git checkout stage] => 136 [vagrant halt] => 125 [git pull origin stage] => 111 [vagrant ssh] => 106 [git checkout master] => 92 [git checkout prod] => 87 [git diff] => 78 [git checkout dev] => 78 [git pull origin prod] => 73 [git pull origin master] => 70 [git checkout integration] => 69 [git merge stage] => 66 [git reset HEAD --hard] => 60 [git pull origin dev] => 57 [git merge dev] => 57 [git checkout preprod] => 55 [git pull origin integration] => 55 [git commit] => 49 )
看起来我运行'gitstatus'的次数比其他git命令要多得多。查看我已安装的别名,我意识到我可以使用OhMyZsh别名“gst”来缩短它,我现在需要记住使用它。我确定我只是使用肌肉记忆输入“gitstatus”并且已经习惯了输入。除了git之外,我还经常使用vagrant,但也会在其中看到一些文件系统导航命令。
深入挖掘一下,我决定看看我运行了哪些命令,以便更好地了解我倾向于重复的事物类型。这意味着稍微调整上面的脚本,以便我找出我一个接一个运行的命令。
$stdin = fopen('php://stdin', 'r'); $commands = []; $adjacentCommands = []; //提取命令。 while (false !== ($line = fgets($stdin))) { if (strlen($line) > 300) { continue; } $command = preg_replace('/(\d+\*?\s{1,2})/', '', trim($line)); $commands[] = $command; } //查找并发命令。 foreach ($commands as $id => $command) { for ($i = 2; $i <= 5; $i++) { if (isset($commands[$id - $i])) { $key = implode(' && ', array_slice($commands, $id - $i, $i)); if (!isset($adjacentCommands[$i][$key])) { $adjacentCommands[$i][$key] = 1; } else { $adjacentCommands[$i][$key]++; } } } } //打印报告。 foreach ($adjacentCommands as $number => $adjacentCommand) { echo 'NUMNER:' . $number . PHP_EOL; arsort($adjacentCommand); print_r(array_slice($adjacentCommand, 0, 10)); }
在玩过按顺序运行的命令数量后,我发现5似乎是一个不错的数字,不止于此,它会产生很多我只运行过一次的命令序列,这对我来说没有多大意义自动化。我使用“&&”将命令串在一起,因为这意味着如果需要,命令序列实际上可以按原样使用。
虽然这里有相当多的输出,但我需要删除其中的一些,因为有一些命令序列会进入客户端工作,我不能在这里重复。这是我可以显示的输出。
$ history | php history-report.php Number: 2 Array ( [cd .. && ll] => 107 [git checkout stage && git pull origin stage] => 100 [git status && git log] => 75 [cd vm && vagrant up] => 72 [vagrant halt && cd ..] => 67 [ll && cd ..] => 55 [vagrant up && vagrant ssh] => 54 [git checkout integration && git pull origin integration] => 53 [git status && git diff] => 53 [git reset HEAD --hard && git status] => 50 ) Number: 3 Array ( [ll && cd .. && ll] => 31 [cd vm && vagrant up && vagrant ssh] => 29 [git status && git reset HEAD --hard && git status] => 28 [exit && vagrant halt && cd ..] => 22 [git status && git addcomposer.json&& git add composer.lock] => 19 [cd .. && ll && cd ..] => 19 [vagrant halt && cd .. && ll] => 18 [vagrant up && vagrant ssh && vagrant halt] => 16 [vagrant ssh && vagrant halt && cd ..] => 16 [ll && cd var && ll] => 16 ) Number: 4 Array ( [cd vm && vagrant up && vagrant ssh && vagrant halt] => 10 [vagrant halt && cd .. && ll && cd ..] => 9 [vagrant up && vagrant ssh && vagrant halt && cd ..] => 8 [cd .. && ll && cd .. && ll] => 8 [cd vm && ll && cd var && ll] => 7 [cd vm && vagrant up && vagrant ssh && cd ..] => 7 [git status && git addcomposer.json&& git addcomposer.lock&& git add vendor/] => 6 [git status && git addcomposer.json&& git addcomposer.lock&& git status] => 6 [git checkout prod && git pull origin prod && cd vm && vagrant up] => 6 [ll && cd vm && ll && cd var] => 5 ) Number: 5 Array ( [cd vm && vagrant up && vagrant ssh && vagrant halt && cd ..] => 6 [ll && cd vm && ll && cd var && ll] => 5 [git status && git reset HEAD && git status && git reset HEAD --hard && git status] => 4 [vagrant halt && cd .. && ll && cd .. && ll] => 4 [cd .. && ll && cd .. && cd www && ll] => 3 [exit && vagrant halt && cd .. && ll && cd ..] => 3 [cd someproject && git checkout prod && git pull origin prod && cd vm && vagrant up] => 3 [cd vm && vagrant up && vagrant ssh && git status && cd ..] => 3 )
很明显,我是个白痴。数据就在那里。我运行了多少次'cdsomething'然后是'll'?嗯,这个数字确实存在,所以至少有107次。使用它,我还可以看到我倾向于使用“gitstatus”作为支撑,以确保在运行某种破坏性命令之前和之后我的gitrepo的状态。
撇开悲观情绪不谈,我可以看到这里可以节省一些时间。我倾向于运行命令来结账,然后更新git分支很多,所以自动化这将是节省我一些输入的第一步。除此之外,我还可以通过在每次目录更改后运行目录列表来节省一些输入。碰巧我已经写过关于在过去更改目录后列出目录内容的内容,因此我将尽快将其添加到我的bash配置文件中。
你的结果是什么?您一遍又一遍地运行相同的命令序列多少次?在下面发表评论,让我知道我并不孤单!