Mastering Bash and Terminal
blockloop.io
blockloop.io
For example
:!ls
will execute ls and show you the result (press enter to return) :r!ls
will read the result of ls in for youMore usefully
:r!sed -n5,10p that/other/file
will read lines 5-10 from that other file.However you will most often want to
:!make
:!up build
:!git status
:!git commit -am "Fixed #23"For example, when reading xml I use xmllint to clean it up:
:%!xmllint --format -I don't find myself using ! commands when I know there are multiple commands that I need to run (like your last example). That's usually when I'll suspend and then use the command line.
Could you elaborate on "wreak havoc on your vim session?" I wasn't aware that suspending the process and bringing it back into the fg would harm anything.
You can even use :w in combination with !. For example
:w !xclip
to write the vim buffer contents to the clipboard. You could visually highlight part of the buffer and do the same thing for just the text you want. "*y
"+yOne advantage of the method you describe is that it can be limited to just part of a line. Piping output to xclip is limited to complete lines of text due to the nature of :w !.
That's when I run !bash, enter my list of commands, then exit.
:shell :r !git status -v
And at the to of the result, type my formatted git commit message, visually highlight the message I just typed, and then use the following vim command :r !git commit -F -
Which reads the commit message from standard input.Try emacs with magit. It's really great.
:0r! grep -rn $pattern $path_to_directory
or any other command that outputs lines containing "$path_to_file:$line_no" (eg most linters).With that output read into a buffer, placing the cursor anywhere in the "path:line" part and hitting ^wF will open that file in a new split window, and jump the cursor straight to the indicated line - or you can do ^wgF to do the same in a new tab page.
It's a very handy way to work through a big list of work items spread across many files. You do need to coax the right format for it out of your tools, but fortunately "path:line" is pretty de-facto standard.
(Incidentally, I do ":0r" so it inserts the read-in lines at the very top of the file - just ":r" in an empty buffer leads to a leading blank line, which I find irrationally annoying.)
The trick I described is more for when you're dealing with some unusual program that wouldn't work with :grep - at least not without fiddling with 'grepprg' to invoke it, and/or 'grepformat' to correctly interpret its output.
:cfile
:cbuffer
one can turn that file/buffer directly into a quickfix list, where simply enter will take one to the relevant position. Messages with column positions are recognized in quickfix lists (:help errorformat). :cex system('git grep -n foo | grep bar') | copen
then :cn and :cp to step through the list easily.1G (to go to top of file if not already there)
!Gsort (to filter all the lines in the file through the sort command, and replace the file contents with the sorted lines)
which says: filter all the lines would be traversed over as a result of running the G command (which goes to the last line in the file) through the sort command, and use the output of the sort to replace all the lines that were filtered;
sort can be replaced with any other command that is a filter, e.g. fmt, grep, sed, many more;
(note: no need of colon in the above command, just have to be in command mode, not input mode, which you get into by pressing Esc).
Very powerful, just that feature, particularly in programming.
For that reason I just jump out with a ctrl+z and when I'm done I'm back in with a fg!
Is there a difference?
IMO, :make is (usually) better, because it adds errors to the quickfix list, and put your cursor on the first error location.
https://vi.stackexchange.com/questions/6679/terminal-setup-w...
I am an avid emacs user though. I really should check out vim.
have a look at :cw[indow]
vim can be thought of as a visual and interactive helper for your text-processing utilities. The "intended scope" of vim is text editing, and while you're editing you may want to run commands on the text in your buffer, or just parts of it, and have the results apply immediately without writing and reloading the file, or exiting.
For example, in vim, you may be writing a list somewhere in your document, and you realize you want it sorted alphabetically. You can visually select the range of lines ('<,'>) that comprise the list and then sort them by calling the sort utility [1]:
:'<,'>!sort
And then you can continue adding to the list.What would your workflow be for the above? Some like this...?
1. write the file you are working on in your EDITOR
2. make a mental note of the absolute line numbers for the list in the document
3. open new terminal
4. call an awk command that uses `sort`, or some other script, passing in your line numbers, and the file name
5. switch back to EDITOR and reload file
----
[1] Of course vim has its own `sort` command, so you can leave out the '!' in that example to do the same.
vi did not have its own `sort`, so people used the external `sort`. vi also didn't have the visual selection, so people could pick lines using ranges:
:.,+10!sort
i.e. sort from the current line to the line 10 lines down, inclusiveOne interesting feature many people may not know about is that it's possible to address lines using a regular expression.
For instance, if you had the following text in a vim buffer:
one
two
three
four
five
and you wanted to delete the lines between "two" and "four" inclusive, you could run the following command in vim: :/two/,/four/d
You could also do the same thing in sed sed '/two/,/four/d' filename :make
nowadays rather than :!make Ctrl-r search history
- then Ctrl-r again to show next match
- then Tab to show all options
Ctrl-p previous command or arrow up
Ctrl-n next command or arrow down
export HISTCONTROL=ignoreboth:erasedups
Add to .bashrc to avoid duplicate entries
Ctrl-a to beginning of line
Ctrl-e to end of line
Alt-b one word back
Alt-f one word forward
Ctrl-k delete to end of line
Ctrl-u delete to beginning of line
Alt-d delete to end of word
Ctrl-w delete to beginning of word
Alt-Backspc same
cd - change to last dir
pushd <dir> mark current dir and go to <dir>
popd go to marked dir
z fuzzy cd, install from https://github.com/rupa/z
j fuzzy cd and more, install via autojump
Ctrl-z to background & suspend
bg recent background app continue running
fg bring recent background app to front
disown -h remove recent background app from current tty
fg %n bring nth app to front, e.g.: fg %2 for second
less better than cat, doesn't flood screen, same keys
find find files, e.g. find / -name <filename>
ag install via the_silver_searcher, faster grep
tree shows dir like a GUI app, install
!! last command, e.g. sudo !!
fish bash alternative with more sensible defaults
man bash read more about bash* zsh bang
previous commands:
!! Previous command
!-1 Previous command
!-2 Second previous command
Getting individual arguments: !$ Last arg
!* All args
!$:h Last argument, strip one level
!!:1 First arg
Modifying commandlines !ls:$:h Head
!ls:$:t Tail
!ls:$:r Rm Suffix
!ls:$:s/user/dude/ Substitute user by dude
* Filename Modifiers :h head (dirname)
:t tail (basename)
:e extension
:r remove extension
:l lowercase conversion
:u uppercase conversion
:p print command but do not execute
:q quote substituted words
* zsh globbing **/* Picks out all files and directories, recursively.
***/* Ditto, following symlinks
* Any string, including the null string.
? Any character.
[...] Any of the enclosed characters. Ranges of characters can be specified by
separating two characters by a -.
[^...] Inverse
[!...] Inverse
<x-y> Any number in the range x to y, inclusive. Either can be omitted.
^x Anything except the pattern x.
x|y Either x or y.
x# Zero or more occurrences of the pattern x.
x## One or more occurrences of the pattern x.
globbing qualifiers* file type
(.) Regular files
(/) Directories
(@) Symlinks
(=) Sockets
(p) Named pipes
(%) Device
(%b) Block devices
(%c) Character devices
* permissions (r) Readable by owner
(w) Writable by owner
(x) Executables by owner
(R) Readable by world
(W) Writable by world
(X) Executable by world
(A) Readable by group
(I) Writable by group
(E) Executable bu group
alternatively a chmod style syntax is supported: ls **/*(.:g-w:)
* Ownership (U) Your own user
(G) Your own group
(u:userid:) User with userid
(g:userid:) group with groupid
example: list files belonging to user www-data with ls -l /(u:www-data:)Modification and access time
(m) Modification time
(a) Access time
(-) Before
(+) After
(M) Months
(w) Weeks
(h) Hours
(m) Minutes
(s) Seconds
example: list files accessed last month with ls /(.aM-1)file size
(L) File size (defaults to bytes)
(k) use kilobytes
(m) use megabytes
(p) use 512-byte blocks
example: list all files larger than 10 megabytes with ls /(.Lm+10)dos2unix /~.(gif|png|jpg)(.) # ~ excludes
dos2unix (#i)/~.(gif|png|jpg)(.) # case-insensitive
ls =bob # Lists file anywhere in $PATH
ls /some_file # Lists file under current directory zargs -- /(.) -- ls -l # Ditto
* zsh Iteration
for i (/home/**/q*) rm $i
for i in /**/b*(u:miklophone:); do rm $i ; done
for f in http://zsh.sunsite.dk/Guide/zshguide{,{01..08}}.html; do...
zargs -- /**/b*(u:miklophone:) -- rm
* Renaming files with ZshNumerical prefix:
$ i=1; for j in *; do mv $j $i.$j; ((i++)); done
$ i=1; for f in *; do mv $f $(echo $i| awk '{ printf("%03d", $0)}').$f;
((i++)); done
$ integer i=0; for f in *; do mv $f $[i+=1].$f; done
Rename all files from name.mp3 to Name.mp3: $ zmv `([a-z])(*).mp3` `${(C)1}$2.mp3`
Capitalize file $ zmv '([a-z])(*).pdf' '${(C)1}$2.pdf'
Replaces spaces with underlines $ zmv '* *' '$f:gs/ /_'
FOO to foo $ for i in *(.); mv $i ${i:l}
Rename pic1.jpg to pic0001.jpg ... $ zmv 'pic(*).jpg' 'pic${(1:4::0:)1}.jpg'
$ zmv '(**/)pic(*).jpg' '$1/pic1:4::0:)2}.jpg' # recursive
Remove spaces from filenames $ for a in ./**/*\ *(Dod); do mv $a ${a:h}/${a:t:gs/ /_}; done
Substitute r for l s/l/r[/]
Unless preceded immediately by a g, with no colon between, the
substitution is done only for the first string that matches l. For
arrays and filename expansion, this applies to each word of the
expanded text.
The left-hand side of substitutions are not regular expressions,
but character strings.
Any character can be used as the delimiter in place of '/'. A
backslash quotes the delimiter character.
The character '&', in the right-hand-side r, is replaced by the
text from the left-hand-side l. The '&' can be quoted with a
backslash.
* zsh if
# see also -z below if [[ $foo = '' ]]; then
print The parameter foo is empty
fi
# quote the term to avoid pattern matching (not regexp, btw) if [[ biriyana = b* ]]; then
print Word begins with a b
fi
# Numbers if [[ $number -gt 3 ]]; then
if [[ $number -lt 3 ]]; then
if (( $number > 3 )); then
if (( 3 )); then
# Files if [[ file1 -nt file2 ]]; then # newer than
if [[ file1 -ot file2 ]]; then # older than
if [[ file1 -ef file2 ]]; then # same file
# Variables if [[ -z "$var is blah; test fails" ]]; then # zero length?
if [[ -n "$var is blah; test passes" ]]; then # non-zero length?Here's a simple example: [2], but it can get arbitrarily complex -- in a much more visual and interactive way than what a shell alone would be capable of.
[1] - http://manpages.ubuntu.com/manpages/wily/en/man1/qmv.1.html
[2] - http://unix.stackexchange.com/questions/1136/batch-renaming-...
Ctrl-k delete to end of line
Ctrl-u delete to beginning of line
Alt-d delete to end of word
Ctrl-w delete to beginning of word
Alt-Backspc same
Bash keybindings behave like Emacs by default, hence every time you invoke one of these, it will put the string into a buffer, which can be later pasted using Ctrl-y.This is very useful. For instance, if you remembered that you didn't `mkdir /mnt/disk` while in the middle of the command `mount /dev/sdb /mnt/disk`, you can delete what you have already typed with Ctrl-u; issue `mkdir /mnt/disk`; than you can paste the previous command with Ctrl-y. Very useful and I use it all the time! (Ctrl-u have never tied to my muscle memory, so I usually do Ctrl-a Ctrl-k to move to the beginning of the line and delete what comes next).
Other tips:
cd goes to home dir
Ctrl-] moves cursor to character (such as vim f)
Ctrl+Meta+] moves to character backwards (vim F)
I also put these in my .bashrc for searching history pressing up/down. "\e[A": history-search-backward
"\e[B": history-search-forward
This is different of searching with Ctrl-r. When you type part of a command, such as mkdir /dev
and press up, it will complete with previous ocurrences of commands starting with `mkdir /dev`. It is faster than Ctrl-r if you already know what to do. "\e[A": history-search-backward
"\e[B": history-search-forward
These have to go in `~/.inputrc`, right?> I know there are some cool newcomers out there like zsh and fish, but after trying others out I always found that some of my utilities were missing or ill-replaced.
First of all bash was first released in 1989 and zsh arrived just 1 year later so zsh is in no way a newcomer.
Secondly zsh is almost strictly a bash superset so I don't know what he was missing (or what he found "ill-replaced").
I would have to run zsh again to remember the pieces that I didn't like. I might have been able to configure my way around it, but I do remember things not working as I expected them to.
zsh has always been held back by the "default browser"-syndrome: Linux and Mac OS both come with "good enough" default shells, so few people actually want to go through the effort of switching.
Especially since there is a bit of a learning curve to becoming more productive with zsh than you already are with bash.
It's one reason to keep one's environment relatively standard and boring. Otherwise, one comes to be dependent -- psychologically, at least -- on one's meticulously configured custom environment, and either chafes at its absence elsewhere or spends a great deal of time copying it everywhere.
Bash and zsh only differ in some of their more advanced features, which I rarely use or miss on machines I ssh in to -- unless I spend most of my time on those remote machines, in which case I'll just install zsh there too. The main thing from zsh that I do miss on bash is advanced globbing, which is more convenient than the find command, but when I'm forced to use bash I'll just use find, and it's really no big deal.
So I encourage you not to let the fact that most machines have bash installed on them deter you from switching to zsh, if you're interested in zsh. I know I regret the years lost that I didn't use zsh myself.
IIRC debian provides a checkbashisms to know which scripts will pose problems when ran against /bin/sh
Anyways. The core point is that compatibility often means compatible in 90%-99% of the cases. It's really really hard to be 100% compatible, which also requires one to emulate bugs etc.
I like to come up with one-liners when doing stuff as a challenge and not being able to do a for-loop as a single line drove me nuts (keeping it one line is really useful when you're iterating over a command and using history). I also find subshells very handy in bash.
It requires some work to build zsh settings to one's personal preferences but once done you are at home. Alternatively you can use one of the many settings you can find around, it is faster and simpler but now you're living in someone else' home.
On the other hand, if you look at the whole widgets section, I'm pretty sure you could hack it yourself since zsh supports used defined widgets (widgets are basically functions used by the zsh command editor).
I never said that it's easy, just that zsh is basically a bash superset. However that does mean that in some occasions this means that you want a Prius and instead get a Ford Mustang kit that you have to assemble yourself :D
bindkey '^]' vi-find-next-char1. Ancient.
2. Will most likely never be updated by Apple
(Most GNU- and Linux-based systems, and also Windows, on the other hand, continue to use the latest versions.)
Nevertheless, I updated the post to add bash 4 to the assumptions.
http://meta.ath0.com/2012/02/05/apples-great-gpl-purge/
[…]
Anyway, the message is pretty obvious: Apple won’t ship anything that’s licensed under GPL v3 on OS X. Now, why is that?
There are two big changes in GPL v3. The first is that it explicitly prohibits patent lawsuits against people for actually using the GPL-licensed software you ship. The second is that it carefully prevents TiVoization, locking down hardware so that people can’t actually run the software they want.
So, which of those things are they planning for OS X, eh?
I’m also intrigued to see how far they are prepared to go with this. They already annoyed and inconvenienced a lot of people with the Samba and GCC removal. Having wooed so many developers to the Mac in the last decade, are they really prepared to throw away all that goodwill by shipping obsolete tools and making it a pain in the ass to upgrade them?
if [ -t 1 ]
then
# search for commands that start off with the same characters already typed
bind '"\e[A":history-search-backward'
bind '"\e[B":history-search-forward'
fi
One of my friends also recommended version-controlling your config files and storing them on gitlab, which I'm only sad I didn't do sooner. It's been such a help in keeping my aliases and configs in sync, as I make changes across numerous different machines.Also, the author does not mention hitting tab for autocomplete (or displaying the remaining options that match what has been typed so far).
Substring history search, so you can use just a substring to look for a argument,command. Binded to ctr+r/s by default. ;)
https://github.com/liloman/asyncBash#use
Changing directories: Last n directories, transparent popd/pushd.
https://github.com/liloman/dirStack
Movements: vim-surround for your cli, so you can do ysiw" o whatever... ;)
https://github.com/liloman/bash-surround
Control-n right: So just type the start and control+n to search for the arguments/commands starting with whatever. And the classical up/down to look up for a complete history line:
https://github.com/liloman/dotfiles/blob/master/bash/.inputr...
https://github.com/liloman/dotfiles/blob/master/bash/.inputr...
There're a ton of hidden functionality and customization behind the classical bash instalation. :)
I'm gonna steal some ideas from asyncBash
I don't understand why the default bash/readline doesn't get something related for substring search or way better autocompletions, it's really not that hard definitely (actually quite easy) and even when that's the reason for a lot of people to choose zsh over bash.
While there is much useful in this post, I always find comments like this one odd. bash was released back in 1989, zsh was released one year later, in 1990. One year difference in age almost thirty years ago means that you can't really call zsh a newcomer. Maybe he's talking about adoption, though.
Some people just lack the perspective.
Tracks your most used directories, based on 'frecency'.
After a short learning phase, z will take you to the most 'frecent'
directory that matches ALL of the regexes given on the command line, in
order.
For example, z foo bar would match /foo/bar but not /bar/foo.I would have liked to maybe start using the command you linked but unfortunately it is using the WTFPL so I will have to pass on it. But from the short description you quoted maybe I'll implement a similar tool myself some day. Then again maybe I will just keep doing things the way I'm doing them now because usually most of what I do is I go to a specific directory and do a lot of work there without moving much, typically said directory will be the root of the repository I have for what I'm working on. If I'm working in several project root directories at the same time I'll usually have multiple terminals open.
With fish I have a setup.fish script that defines all my universal exports, for when I setup a new computer. This is for private tokens, like HOMEBREW_GITHUB_API_TOKEN. For aliases and utilities, I wrote a fisherman [0] plugin. It has a functions folder and a fishfile for the few other plugins I use.
Many CLI tools are missing completions, but I think it's slowly getting better over time. The pros outweigh the cons for me.
https://github.com/zsh-users/zsh-syntax-highlighting
If you want to delete everything and don't want to keep typing yes just do `yes | rm bla`.
$ rm -fi blah
remove blah?
$ rm -if blah
$ # confirmation suppressed rm -i x y z -fI'm not sure I agree with that. If you work in a decent IDE and your vcs is not git then you can do pretty well without a terminal. Especially on Windows.
Whether the reader knows that meaning immediately is a rather good proxy for just how long they have been working and/or playing with computers. Long ago, in a world of RS-232 connected display terminals and/or analog telephone modems, one became very familiar with "XON/XOFF flow control".
For me, as far as shells go it's usually enough to know the basics and be able to look stuff up when debugging other people's shell scripts.
On my personal machines, I often find places where I want to either clean up my desktop experience or automate some workflow, where I break some shell out. Most of the time, the overhead to drop into an actual programming language is quite heavy, and even though I try to comment my scripts and write them in a maintainable fashion, I only end up editing them maybe a few times a year.
I feel like discouraging shell scripts is part of what's driving us to seek increasingly heavyweight solutions like systemd in our architecture. Sometimes a lightweight environment where we trust the programmer is needed.
Brevity and simplicity are really the keys when it comes to shell scripts. I really don't have a problem with them if they're short and don't try to be too clever. Whenever I've let my shell scripts get long or complicated, I've always regretted it, and always wound up rewriting them in a "real" programming language anyway, and then realizing that I would have been better off rewriting them much earlier, as soon as they'd outgrown the short, simple stage.
There's no shortage of relatively light-weight "real" programming languages like Perl, Python, Ruby, Lua, and Go -- for even moderately sophisticated tasks, all of them would be better choices than shell scripting.
#> watch -n 1 dmesg & #> fg -- brought it back
ip addr show en0 | grep -inet\ | awk '{ print $3 }' | awk -F/ '{print $1}' | pbcopy
you can use: ipconfig getifaddr en0
If you wanna stick with ip addr, a more compact command is: ip addr show en0 | awk '/inet/{split($2,a,"/"); print a[1]}'My bash history does not reflect my use of multiple terminals.
LESS=+/"DEFAULT KEY BINDINGS" man readline
assuming it exists on mac.
About suspend, what's the benefit of suspending vim using C-z? Shouldn't you use a terminal multiplexer instead, or even terminal tabs if you don't want to learn how to use tmux or screen (which I find weird if you already spent time to learn how to use vim but alright)?
I only ever suspend a program when I want it to stop, for instance because it slows other programs and I realize I would rather resume it when I'm not in front of my computer. Even in that case, I often just renice the program instead. Stopping a program just because you want to run some bash commands looks like an anti-pattern to me, but maybe there are better motives I'm not aware of.
bindkey -v bindkey -M viins 'jk' vi-cmd-mode
Then you can edit your command line the same way you would edit a line in vim.
Notably they don't work in MS Office, but they work in web browsers and practically every other app I have on my Mac.
These days bash seems to have a lot closer feature parity to zsh, and I'd be curious to read an up-to-date comparison of both shells to determine if either is clearly better than the other.
Back in uni I used to use tcsh interactively, script in [ba]sh, and program in a "real language" like C, Java, etc., but I wasn't doing anything very complicated with any of them. Once I started working and begin using these tools seriously, I simply couldn't learn and retain all of them. Something had to go, and tcsh was it.
Sounds like the author never heard of Windows development.
What? No. Use Ctrl-f and Ctrl-b. I use this probably more than any other readline shortcut.
Ctrl-h for backspace, Ctrl-d for delete. Half my keyboards don't even have arrow keys and I don't miss them.
He means “ctrl-w”. But since that only works in bash, not in Emacs or other tools with Emacs key bindings, it makes more sense to use (in his terminology) “alt-backspace”. This does the same thing, and works both in the shell and in Emacs-like environments.
So, for me, it works in both shell and editor.
sudo !!
In the same way, "!*" is all the arguments of your previous command, and "!$" only the last one.Also there's a big difference between Alt + Backspc and Ctrl + w. The first will delete a word consisting of only alphanumerics, while Ctrl + w also deletes the word, but word can be made of any characters other than space.
Don't ctrl-f and ctrl-b work?
Alt-l converts next word to lowercase
Alt-u converts next work to uppercase
Option + Cursor-Left/Cursor-Right to jump words
ctrl-r search in history, ctrl-r again to skip-
ctrl-p previous command (instead of arrow up)
ctri-nmc allows to explore system efficiently while not standing in my way, because I can always press ctrl-O and get my shell back.
bash-completion saves time on typing of commands.
Other tools I install often are htop (better ps) and strace.