Today, was actually the first time that I used the vim time travel feature. I noticed that I had deleted a line by accident somewhen during the last few minutes. So I typed
:earlier 5m
and copied the line. Afterward, I typed
:later 5m
and was back where I started, ready to paste the missing line :-)
It automatically makes a list of directories you frequently use in your shell and if you type `z a-small-substring-of-the-directory-path` it does a cd to that directory. (e.g. I type `z and` and it changes my current directory to $HOME/Work/Projects/android`). Saved me tons of typing.
CDPATH doesn't require the export as it is local to the shell session. Simply setting it will work as you'd want and won't pollute the environment for subshells and scripts.
And zsh users get another advantage here. You can use assign to the cdpath array or the CDPATH colon-delimited string, they are both treated the same internally. The advantage is being able to `cdpath+=...`, much like adding to $PATH with `path+=` or removing from PATH with `path^=`. Check zshbuiltins(1) for how to make your variables work like this, or how to use typeset -U to remove duplicates automatically, or $thousand_other_cool_things.
Note that CDPATH can break shell scripts that assume `cd` hasn't been adulterated.
A huge block of "unalias" calls at the beginning of shell scripts used to be a common practice, but they don't seem to be found in more widely-used tools these days.
What is /usr/bin/cd for? cd is supposed to be a shell built-in, because running /usr/bin/cd will make another process and that cannot change the current working directory of the shell you are in.
Have you checked out Warp drive for zsh? https://github.com/mfaerevaag/wd It is more manual than z, but takes out the learning phase. Will check out z though!
It depends on how you work, I have a lot of small projects which come and go, so setting up the paths every time I start or finish something would be inefficient.
Although I might adopt it for different weird system configuration directories which I often forget the path to.
Yes I have had that problem already, more specifically cleaning the lists in wd if directories are moved or removed. I do a cronjob to try to rectify that but interested to see if z mitigates this problem - seems there is an option -x to remove learned directories.
[edit] Or z's based ageing ranking system will just aged those legacy directories, even better (in terms of more hands off)!
The advantage of autojump - at least for me - is that it doesn't depend on the shell, as it is implemented in Python. This makes it possible to read and write the data elsewhere, too, independent of your shell.
For example, I integrated it into ranger (see my history, I don't want to spam HN with this project).
I use autojump, but I liked the idea of having an fzf-powered menu pop up when invoked without any args (which is not how autojump behaves). So I made rustled this up (zsh): https://pastebin.com/aLmqJVRy
I rarely use Ctrl+r to get command from history, because most of the time I know the starting characters of the command I need. So, I type those characters and use arrows keys to match from history. This is enabled via these settings in .inputrc
# use up and down arrow to match search history based on typed starting text
"\e[A": history-search-backward
"\e[B": history-search-forward
I also changed couple of setting wrt Tab autocompletion:
# when using Tab for completion, ignore case
set completion-ignore-case on
# single Tab press will complete if unique, display multiple completions otherwise
set show-all-if-ambiguous on
You can use ctrl+r for commands which are similar (say ssh to n number of servers, so the up/down would still take some amount of browsing the options)
When I used bash, I had all of your settings on (had more, some others I can live without - these four I can't). I still have them in .inputrc for programs that use readline!
I have since switched to zsh. Up/down to search history, in ~/.zshrc:
The primary reason I chose over zsh/bash was that autocompletion just works. If you install it, I highly recommend oh-my-fish as well, which allows you to add packages for look/functionality:
https://github.com/oh-my-fish/oh-my-fish
Another vote for fish. I would say another benefit is that it has a reasonably great out of the box experience with little customization needed to get a lot of its benefits, eg awesome autocomplete.
The downsides have been mentioned, namely the lack of compatibility with shell scripts not written for it. In the same vein, until somewhat recently, operators like && did not work for it.
It’s still my daily shell, and I really only use something like bash when having to remote into a production server.
I really enjoyed using fish for a short while, but soon I learned that it was not POSIX compliant. This was a deal breaker for me since my colleagues would often share scripts that wouldn't just work for me. I use zsh nowadays.
I love zsh, but it isn't without its own strange quirks that make compatibility exciting at times. In a thread from a fortnight ago¹, RANDOM is handled very differently for example. Try `echo $(echo $RANDOM) $(echo $RANDOM)` in zsh and bash.
I'm unsure whether minor differences that catch you out occasionally are worse than huge differences that you always have to think about. For me zsh still wins ;)
Without the same fluency in bashism from using it for day-to-day activities, the colleague provided script is less readable and less editable for the fish-fluent, bash-inarticulate. Any fish-specific scripts are also of low-value to colleagues.
It's not that it's impossible to be a shell polyglot, but GP deemed it easier to learn !fish.
I tried fish for a while and loved the history recommendation mechanism, but the 'vi mode' emulation had enough annoyances that I went back to zsh. From the bugs filed on it, it seems like the vi fixes weren't really possible.
I did install a similar history recommender in zsh and have been pretty happy with that.
> If you want to remove a sensitive command from your history, you can simply edit your $HISTFILE history file and remove it.
It’s already too late at this point. Anybody on your machine can read the commands you are running, for example with ps. You should instinctively avoid entering anything in plaintext into a terminal which you don’t want other people to see. Any command line tool worth its salt will provide alternative ways of passing secrets (using configuration files for example).
The worst is when you expect a password prompt so you type the password and hit enter, but you mistyped the original command and you end up typing your password in plaintext onto the command line. oops.
If you're using `bash`, A quick remedy for this is:
unset HISTFILE
exit
This prevents `bash` from updating the `~/.bash_history` file on exit with the command you don't want memorialized. (assuming you don't also have some hook that updates your history file after every command)
I understand what you're saying but if anybody on your machine can read the commands, can't they also read your configuration files? Or are you saying a different user on the machine can run `ps` and see my processes but not necessarily my portion of the file system? My thought is if the file is not encrypted on the disk, then any desktop application can read it. So, while I agree that preventing a user from reading bash history is not worth it if they can read your processes, aren't configuration files (if unencrypted) just as insecure?
Indeed! One thing that at least works on zsh is to prefix the command with a space, then the command doesn't go into the history file.
So if you do `date`, it'll end up in the history file but if you do ` date` (one space prefixed), it won't. One `clear` later and it's like the command was never run.
> Anybody on your machine can read the commands you are running, for example with ps.
This is why I always mount /proc with the "hidepid=2" option (as well as the "gid=<n>" option to ensure that doesn't apply to the members of a specific group, such as the "admins" of the box).
I think what OP meant was closer to "if it could have been entered into the bash history than there's other ways it could be seen".
Most CLI programs that need sensetive information as input should either do it interactively (a la sudo), as standard input, or configuration file. If worst comes to very worst, you can put the sensitive info in a text file and use backticks. For example:
https://github.com/zsh-users/zsh-autosuggestions also looks through your history for commands with the same start, but it will automatically suggest them for you to use. If you often use the same commands, this saves quite some typing. For bonus points, I hooked it up so that Ctrl-Return will execute the suggestion.
I'm a huge fan of the first 2 plugins, but I didn't know about the per-directory history plugin. I might put that in my toolbox. Thanks for the recommendation!
is not "expanded to all files and directories in the children directories, with a depth limit of 1." It's hard to see using `ls` because `ls` doesn't just list its arguments, it also lists files inside its directory arguments. Use
echo **
and you'll see it just expands to the same as
*
- all the files in the current directory. Or type
**
and press Ctrl-x, Ctrl-* (glob-expand-word) to expand it.
After `shopt -s globstar`
**
expands to all files recursively.
Also, `echo $dir | tr '[:lower:]' '[:upper:]'` should be `printf '%s' "$dir" | tr '[:lower:]' '[:upper:]'` to handle spaces and other weirdness in file names.
(If anyone knows how to escape asterisks in HN it would be helpful to know :)
No matter how many times I read articles like this I always manage to learn something new. For example this time I learned about brace expansion. Will save me retyping a bunch of commands with different text.
If you care about your command history, I would advise against doing this unless you are truly a sed expert:
$ sed -i '/secret-command/d' $HISTFILE # deletion of history line containing 'secret-command'
Because if you get it even slightly wrong, you could easily hose your entire history. If it were me, I would just use an editor to delete that line (or two, if timestamps are enabled).
As zsh is mentioned at various points throughout the article I'll add that zargs¹ is often a great alternative to xargs. Combined with zsh's awesome globbing and filtering functionality it is often far nicer to work with than find.
I think zsh is the best shell ever, unfortunately, I've reverted to bash, because it's too much hassle to install zsh everywhere I work. zsh globbing is on another level.
I agree. That said I'll freely admit that liberal use of glob modifiers and qualifiers can lead to the appearance of line noise. Because of that I'll occasionally unroll them with `find(1)`-syntax if I post a snippet to help a co-worker, but love their expressiveness when in an interactive session.
Ctrl+U is also really handy for clearing password (or any other input) lines where you know you made a mistake, but don't want to just spam Backspace until you think you've gotten to the beginning.
The article links to this at the bottom, but just calling it out again because I think it's so useful. I am using git all the time---probably a majority of my terminal relates to git in some way. I think the git bash completion script is extremely useful. https://github.com/git/git/tree/master/contrib/completion
It's incredibly easy (and transparent) to "install" and saves a ton of keystrokes.
Best shell productivity trick ever: don't use the shell for anything more complicated than launching executables and use a reasonably modern programming language to achieve all other tasks.
I'd love a good answer here. Shell is clunky and annoying as hell, but a "better" language like python is very verbose for typical shell stuff like process management (processes, pipes, signal handling), small text handling tasks like regex matching or string splitting.
Perl is maybe the closest here, but it certainly has it's fair share of annoyances, and I more or less dropped perl for python decades ago and don't particularly feel like going back.
Not really, with python there's a habbit-acquiring curve but you end up with longer lasting more readable and maintainable assets that can be modularized refactored etc.
perl is write-only and has little going for it afaic but ymmv.
'rename .txt _1.txt *' is quite a few lines in a language that's super simple, like Python, and it turns into code golf with even more terse languages.
OP might have made their statements tongue in cheek.
But there's the truth in there that even programming languages that are 20 years old had a completely different mindset applied to their design process than the original Unix shell which was much more ad-hoc.
40 years ago IT was a completey different environment than 20 years ago.
Not tongue in cheek at all, python might be 20 years old but is continually developed, has come all the way to have a typing system and has a huge ecosystem for all things devops
About a year ago I went further into this rabbit hole and right now I think I am on a re-iteration of a system I have not changed in about 4 months. It came to me after watching too much sci-fi that had clicky-clicky-typie-typie instant recall.
It occurred to me that every hack around history just nibbles at the edges probably because all of them are bolted on a design when the systems were slow. Systems now are fast and have good connectivity ( at least to themselves ) hence:
"All logins across all systems that have the same security domain share single common command history."
I use bash but it should be adoptable to anything. Here's how it works:
1. There's a database. I use redis because it is fast and has SETNX. [I may switch this to a redis queue to be able to archive commands as well.]
2. Using PROMPT_COMMAND variable I execute a function that pulls the last executed command using "history 1" and pushes it into the database. SETNX ensures that only a command that has not been seen before is stored. In the same transaction I trim the number of commands stored in the database to 5000.
3. Ctrl-R is bound to fetching last 5000 commands from the database, piping it into "peco" which I use with the selection line on a top ("fzf" does not support the top line so I don't use it here. "peco" does not support certain header skips/treatments, so i use "fzf" in other places )
4. On a failure to push into the database, system does nothing as the data is in a local history.
5. On a failure to pull from the database, system feeds the result of the local history into the "peco".
This system gives me ability to access the same command line history across my laptops, workstation, VMs, random Linux devices that i have running at home. Our ops-team uses it across all the monitoring workstations
I use this to have all shells share a history concurrently - which sometimes is confusing if you press "↑" and have an unexpected (possibly dangerous command) but I'm used to it now:
shopt -s histappend
PROMPT_COMMAND="history -a; history -c; history -r"