Unix Commands I Wish I’d Discovered Years Earlier
spin.atomicobject.com
spin.atomicobject.com
ls man pwd cd top ps df du cp mv rm mkdir rmdir less cat vi
[1] https://news.ycombinator.com/item?id=6046682[2] https://news.ycombinator.com/item?id=5022457
[3] https://news.ycombinator.com/item?id=4985393
[4] http://sysadmincasts.com/episodes/13-crash-course-on-common-...
[5] http://sysadmincasts.com/episodes/12-crash-course-on-the-fil...
(Actually, I have found use for those first two on occasion. ;)
tsort takes a list of pairs of node names representing directed arcs in a
graph and prints the nodes in topologi-cal order on standard output.
It's not often I understand nothing on a man page. But this time, I'm stumped!It's a way to do some of what make does without having to write a Makefile. 99.9% of the time, it never comes up, but when it does, it is very, very handy to be able to this in a shell pipeline. HTH.
info coreutils 'tsort invocation'"Man ascii." The number of times that I wound up generating my own ascii table from whatever language I was working with...
"xxd" I always either used search in emacs hex-mode (which I find cumbersome and annoying but haven't taken the time to customize), or rolled my own search using a programming language. This would have come in handy SO many times back when I used to muck around with videogame save files and the like. I never even knew it existed nor how to discover that it did.
'cal' I learned about early on so never missed it and the 'ssh' stuff kind of fits into the regular "unix tips and tricks" category.
You reminded me of something. There is actually a really cool and simple site called asciiflow [1], which I use all the time to draw diagrams for explaining things in email, etc. It's pretty cool, and was even submitted several times to HN [2, 3].
[1] http://www.asciiflow.com/#Draw
$ host www.asciiflow.com
Host www.asciiflow.com not found: 3(NXDOMAIN)
Caused by both authoritative nameservers for asciiflow.com which return the correct answer (a CNAME to ghs.google.com), but with status=NXDOMAIN (wtf?): $ dig +short asciiflow.com ns
ns2.123-reg.co.uk.
ns.123-reg.co.uk.
$ ; <<>> DiG 9.8.1-P1 <<>> @ns2.123-reg.co.uk www.asciiflow.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 65092
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;www.asciiflow.com. IN A
;; ANSWER SECTION:
www.asciiflow.com. 86400 IN CNAME ghs.google.com.
;; AUTHORITY SECTION:
google.com. 14400 IN SOA ns.123-reg.co.uk. hostmaster.google.com. 2013052701 86400 0 604800 86400
;; Query time: 207 msec
;; SERVER: 92.51.159.40#53(92.51.159.40)
;; WHEN: Wed Sep 11 00:27:52 2013
;; MSG SIZE rcvd: 123this time, the very first one `man ascii` got me. Genius. Never though about looking for that in man before. But in my defense, this was added in 1999 :)
I'm sure that was a bit earlier than 1999.
Let's say my pwd is `/home/projects` and i want to edit `/home/projects/a_huge_sprawling_app/940j_394/lol/flight_controller.rb`
`vim **/flight_controller.rb`
opens our flight_controller.rb straight away. In terms of effort, this allows you to basically omit a `find -name` when you're in a rush to edit some damn file where the hell is it again damn we need to reevaluate this directory str...----
Double bang to re-use your last terminal entry. One great use, taking all the pain out of forgetting your sudos
`rm -rf /var/log`
rm: cannot remove `/var/log': Permission denied
`sudo !!`
All evidence of wrongdoing is now destroyed.-----
Ok, here is an awesome one for users of the ultimate cloud IDE: Vim.
In your local ~/.ssh/config:
`ForwardX11 yes`
`SendEnv WINDOWID`
In your remote server's /etc/ssh/sshd_config: `AcceptEnv WINDOWID`
In your vimrc: `set clipboard=unnamedplus`
This has the effect of seamless yank and paste between local and remote vim sessions, no need for ctrl+shift+v.I love linux.
[1]: https://www.gnu.org/software/bash/manual/bash.html#The-Shopt...
Thanks a lot for wising me up to the new hotness offered by bash 4+ (zsh is also pretty slow for me for some reason, even though people keep telling me to switch to that. Maybe I'm more impatient than most folks).
find . -name "*.flv" | xargs -n 1 -P 9 ./process-video.sh
This immediately forks 9 instances of process-video.sh on the first 9 .flv files in the current directory, then starts a new instance whenever a running instance completes, so 9 instances are always in flight. (I usually set to number of cores plus one for CPU-bound tasks, hence 9 for my i7 with eight cores [1].)If you add -print0 to the find command and -0 to the xargs command, it uses null-terminated filenames (which does the right thing when filenames contain whitespace).
[1] Logical cores. Most i7's have four physical cores which become eight logical cores through the magic of hyperthreading.
If you have 8 cores running 8 jobs, then whenever one of those jobs needs to do I/O you have a core sitting idle while that job waits for the disk. If you have 8 cores running 9 jobs, then all your cores will still be fully utilized when a single job is doing I/O.
I think you actually want to do plus a small percentage, perhaps 5%, so ceil(1.05*N) jobs on N cores. That is, I have a gut feeling that 64 cores doing 65 jobs would still result in underutilization, 67-68 jobs would be better (provided the workload doesn't become I/O-limited with that much CPU power, and provided the number of videos to be converted is still much larger than the number of cores, so you don't run afoul of Amdahl's law).
These are really just rules of thumb based on my gut feelings and mental models of how the system works; it might be fun to actually benchmark it and see if my ideas correspond to reality. (You probably want to reboot first, or a bunch of unrelated I/O, to flush the disk cache.)
The idea behind HyperThreading is basically the same as your n+1 idea. A HyperThreaded core has duplicated circuitry to handle state (registers, etc) but not the execution resources. When one thread is stalled/not using the execution resources (e.g., waiting on disk IO, waiting on a fetch from RAM, etc), the other thread is already in processor ready to go and will be executed instead.
Obviously this is a bit of a simplification, but your n+1 idea is essentially already implemented in the hardware.
That said, if enough of your cores are still stalled waiting on disk/memory access and are stalled long enough to make the context switch worth it, it may be beneficial. If not, however, you might actually end up seeing some minor slow down as the processor is forced to switch between the competing processes.
I'd benchmark it.
$ cal | sed "s/.*/ & /;s/ $(date +%e) / [] /"
September 2013
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 [] 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 cal | cat ls --color=never -1Admittedly, I never actually do this because I don't ever care to not see colour (what would be the motive?), but I can understand why the OP does what they do.
Your 'ls' must be an alias for the real ls with some options. For example, mine is:
$ type ls
ls is aliased to `ls --color=auto'
A quick way to run the original 'ls' (not the aliased version), just prefix it with backslash: $ \ls ...
Or: $ command ls ...Example:
ssh username@host "echo $HOSTNAME && sudo somecommand && cat somecommand.log"
There's probably a better way to do this, but in a pinch I can fix a problem on dozens of machines just by altering the host string.
"typing a password on your local machine once, then using a secure identity to login to several remote machines without having to retype your password by using an ssh key agent. This is awesome. "
Sounds awesome, but I really didn't understand what he means. Is he talking about using a certificate (-i option) to log in ?
So you'll need to create an SSH cert first:
ssh-keygen -b 4096 -t rsa -C "$USER created on $(hostname)" -f $USER.key
Keep the private key, that's essential you keep this safe as it's literally your key to access any servers you do the next step for.On each server SSH, append your public key to the of /home/$USER/.ssh/authorized_keys (creating the file if it doesn't exist). It must be the public key!
There'll be better guides online for this stuff so I suggest you have a read through them before blindly pasting the stuff I've posted into your terminal. But it's all quite simple stuff once you've grasped the difference between a public and private key (if you weren't already aware - you may well be)
"ssh-ebT23030"
Meaning that anyone with root access who know the other machines that someone is accessing as well as their username can access those machines.
I've seen cases where in abnormally terminated sessions that file stays around instead of getting deleted when the session ends.
% (cd /foo; tar cpf - .) | ssh bar \(cd /baz\; tar xpf -\)
Or: % cat ~/.ssh/id_rsa.pub | ssh bar tee -a .ssh/authorized_keysSo basically, you get :
(local) (remote)
stdin -> ssh ssh -> stdout
Hope that helps. tar cj $bigdir | ssh host 'tar xj'
That creates a tar.bz2 archive on your machine, sends it over ssh to the remote host, where it's unpacked. Ad hoc compressed and encrypted file transfers made easy. rsync -az $bigdir host:$bigdirOf course, ssh also gives you the output of the remote process, so you can put an ssh command in the middle of a pipeline. My day to day life no longer involves interacting with lots of remote Unix systems, but when it did, it was really, really useful.
% (cd /foo && tar cpf - .) | ssh bar '(cd /baz && tar xpf -)'
or explore something like: % rsync -aSHx --update --delete -e ssh /foo/ user@bar:baz/. ssh-copy-id - install your public key in a remote machine’s authorized_keys for host in h-abc h-def h-ghi h-jkl h-mno h-pqr h-stu h-vwx h-yza;
do
ssh -l root $host "hostname; echo "1.1.1.1 server" >> /etc/hosts";
done
This would iterate over hosts (h-abc .. h-yza) and run the commands "hostname; echo "1.1.1.1 server" >> /etc/hosts". Or maybe use a for loop and scp to push the files out and then run md5 to verify they are correct. It was a hack but useful for a small set of machines.ps. if you are interested in learning about puppet, I have put together a screencast about it @ http://sysadmincasts.com/episodes/8-learning-puppet-with-vag...
for host in ... ; do ssh -l root $host "..." & done; wait
and it's very parallel. All that key exchange takes a while, so it's not ridiculously fast, but it's pretty good. If you've got ControlMaster set up already to be per-host, this might very well be very fast the second time.Piped tar commands do, but are generally inferior to rsync (at least if you ever need to copy more than once). I believe I've heard (here) that piped tar commands can be useful for the first sync (possibly better compression, no overhead of file checksums), then rsync thereafter.
nohup time whatever >whatever.out &
because so many programs behave differently when attached to a tty (like prompting for input) and I just want a plain text log that says when it succeeded or where it blew up. "Toggle hex edit mode
nmap <Leader>h :call ToggleHex()<CR>
let g:hex_mode_on = 0
function! ToggleHex()
if g:hex_mode_on
execute "%!xxd -r"
let g:hex_mode_on = 0
else
execute "%!xxd"
let g:hex_mode_on = 1
endif
endfunction
Stick this in your .vimrc, type something, use \h to convert it to hex, change a value, then \h to convert it back and observe how the text has changed. Not super useful, but a neat party trick.For instance:
pbpaste | fgrep -i "`pbpaste -pboard find`"
To search the copy clipboard with the find clipboard.
xclip -o -selection clipboard … | xsel -b # Copy.
xsel -b | … # Paste.Makes all sorts of hackery possible.
It will also provide encodings for single characters: $ ascii a ASCII 6/1 is decimal 097, hex 61, octal 141, bits 01100001: prints as `a' Official name: Miniscule a Other names: Small a, Lowercase a
ASCII 0/10 is decimal 010, hex 0a, octal 012, bits 00001010: called ^J, LF, NL
Official name: Line Feed
Other names: Newline, \n[1]: http://emacsredux.com/blog/2013/07/05/locate/ (setq locate-command "mdfind")
It's freaking fast and convenient, sorts hadoop reduce results like a champ.
# Deflection Col-Force Beam-Force
0.000 0 0
0.001 104 51
0.002 202 101
0.003 298 148
0.0031 104 149
0.004 289 201
0.0041 291 209
0.005 104 250
0.010 311 260
0.020 104 240
You can chain commands together to quickly get ball park figures. I do this all the time when reviewing log data to get simple counts and look for anomalies. $ cat data.txt | grep -v '#' | awk '{print $2}' | sort | uniq -c
1 0
4 104
1 202
1 289
1 291
1 298
1 311
Let me break this down a little. I cat data.txt, which just prints the contents to the console, I use grep to remove the # header, then use awk to print the second data column, the sort the values for my next procedure, and lastly I use uniq -c, which takes the input and counts all the unique values. So you can see that "4 104" means that 4 instances of 104 were found. I use this often to look at httpd logs for IP addresses or to review sudo commands, etc. Very handy!ps. there are optimizations that could be done here, but that what is great about unix and "one function" utilities. There are many ways to the same destination!
cat data.txt | grep -v '#'
you can do: grep -v '#' data.txt
or you can simplify further by moving the grepping into awk, so that the full command becomes awk '!/#/{print $2}' data.txt | sort -n | uniq -c
sort -n is good to use for sorting numbers. You could probably pull the sort | uniq -c into awk somehow, but I have already demonstrated the full extent of my awk knowledge. One of these days I will get around to actually learning it. sort -n -f 2 <data.txt | awk '!/#/ ... awk '!/#/ {a[$2]++}END{for (i in a) print a[i],i | "sort -nk1"}' data.txt
1 0
1 202
1 289
1 291
1 298
1 311
4 104The funny part is that one of the early uses of Google's map/reduce approach was probably to distribute the job of sorting search results among many servers. And here you are sorting Hadoop results with something as small and simple as sort(1).
The Applescript is this if anyone wants to do something similar:
tell application "Terminal" do script "tail -F /somepath/some.log" do script "tail -F /anotherpath/another.log" do script "sudo fab -f '/pathto/fabfile.py' local deploy" activate end tell
Here's a detailed explanation of setting up Triggers:
http://leafraker.com/2007/09/17/how-to-create-a-quicksilver-...
What's in use here is more widely known as “process substitution”.
echo <(true)
And you'll see the anonymous named pipe created by the subshell and passed to echo.You'll thank me later.
uname -rms
FreeBSD 9.1-RELEASE-p19 amd64
Although the xxd man page doesn't have the BSD label, and is from 1996, so I'm not sure if xxd only recently found its way into FBSD. This manual page documents xxd version 1.7
AUTHOR
(c) 1990-1997 by Juergen Weigert $ xxd
xxd: Command not found.
$ uname -rms
FreeBSD 9.1-RELEASE amd64
edit: fixed typo where I put xdd instead of xxd root@primus:/usr/ports # xxd
xxd: Command not found.
edit:It doesn't show up in my ports either:
root@primus:/usr/ports # make search name=xxd
Port: textproc/xxdiff
Moved:
Date: 2013-07-26
Reason: Has expired: Depends on Qt 3.x
Port: textproc/xxdiff-scripts
Moved:
Date: 2013-07-26
Reason: Has expired: Depends on Qt 3.x
Obviously xxdiff is a different (if you pardon the pun) utility, but xxd should show up in that list also.edit 2:
Another comment on here might explain why you're seeing xxd and I'm not: https://news.ycombinator.com/item?id=6360814 (it's not a separate utility, it's part of vim)
Since I didn't install vim on that box (just use basic vi), xxd wouldn't have installed as part of it. Where as in a jail on the same box, xxd does exist:
root@primus:/usr/ports # which vim xxd
vim: Command not found.
xxd: Command not found.
root@primus:/usr/ports # jexec 1 which vim xxd
/usr/local/bin/vim
/usr/local/bin/xxd $ whereis xxd
xxd: /usr/local/bin/xxd /usr/local/man/man1/xxd.1.gz
I don't see xxd anywhere in my ports tree.Haha... What a trip. This is the sort of thing that I'll end up wasting half a day trying to get an answer to.
$ grep xxd /usr/ports/editors/vim/pkg-plist
bin/xxd $ uname -rms
FreeBSD 9.1-RELEASE-p7 amd64
$ xxd -v
xxd V1.10 27oct98 by Juergen Weigert
Perhaps different builds have different things included?You're right, xxd is included with vim, but as an external program.
Vim provides this capability through the external program xxd, which is included by default in standard distributions of Vim.
My pedantic nature was hung up on the release dates of the respective programs, as xxd predates vim on Unix.
It's even listed as a 'Convert to HEX' item in the Vim GUI menu.
I can't remember how many times I implemented hexadecimal dumps and undumps because I didn't want to coerce od into working the way I wanted.
Summary: man ascii, cal, xxd, ssh, mdfind
:-)
This is how I discovered myself "fsutil" (Windows) :)
Can't they just directly access inodes for high speed counting?
Don't know what you mean by that exactly. But, I'd be stunned if find is actually reading the actual files rather than just reading the directory entries in directory "files". Which is what I'd call accessing inodes "directly"
tree | egrep -o "[0-9]+ file(s|)"
edit: or you could just tail the output (should have thought of this first!) tree | tail -n1Available in most repositories, source code available at: http://mama.indstate.edu/users/ice/tree/
imac:~
$ time find . | wc -l
419191
real 0m37.865s
user 0m0.385s
sys 0m2.611s
imac:~
$ time find . | wc -l
419195
real 0m10.503s
user 0m0.330s
sys 0m1.430sWhat do you do when find cannot handle the sheer number of files, argument too long from the linux hardcoded MAX_ARG_PAGES
We need a dedicated utility that counts inodes.
Also, to count the number of files in a directory, you need to do readdir(), which will get you the names. Then, to see if any of them are directories to be recursed into you need to stat() the names individually. This is all "find" does. How, I'd very much like to know, is this "a nasty hack"?
All we want from find is "count the number of inode entries in this tree branch that are type f". No formatting, no output, just count. That has to be much more efficient.
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux....
That's "time find . | wc -l"
It's going to be disk limited unless you're in cache.
Switching to "time find . -printf '1' | wc -c" lowers overhead to .7 seconds, so roughly 1us/file.
The output from find is a list of filenames separated by newlines. The wc command is reading from stdin and counting those newlines[1] -- wc itself has just two arguments in its argv array here ("wc", "-l"). You will not exceed its argument list. Further, it is not at all a hack to count the number of files this way; rather using pipes to compose functionality is the Unix way[2].
But fwiw, if you want a count of the inodes in use in the entire filesystem, you can get that directly from "df -i".
In any case, as an exercise to the reader, I encourage you to grab the source to find and add the -count output option you desire.
[1] Technically a filename can contain newlines, so this would throw off the count. The fix for that would be to use find's -print0 output option and then pipe to something which can count on the nulls. In practice, you're unlikely to have such filenames.
find . | sed -e 's=/[^/]*$==' | uniq -c
If your locatedb is current, you can use locate for this:
$ locate $PWD | wc -l
That runs in just a hair under a second (0.908s real) for the first instance. 'find' takes a few seconds on first pass (it's got to read from disk), but is surprising fast (0.227s real) on subsequent runs.So I guess it depends on whether you're doing it just once or multiple times.
function lc() { if [[ "$#" -gt 1 ]]; then for DIR in "$@"; do echo -n "$DIR - " ; ls -AU1 $DIR | wc -l ; done ; else ls -AU1 "$@" | wc -l ; fi; }
Then "lc dir/" will print the number of files in the directory, and "lc dir/*" will print the number of files in each of the subdirectories. This exactly what you're looking for because it doesn't descend into the tree. If you're working with directories that may have tens or hundreds of thousands of files in them, it's useful to check first.
Compared to the equivalent find, code #1 is much faster in this completely scientific best of several runs:
$ time (find OSS/llvm -type f -or -type l | wc -l)
real 0m4.681s
$ time du -d0 OSS/llvm
real 0m4.863s
$ time ./fts OSS/llvm
real 0m0.559s
Ostensibly because of the lack of stat calls. On the other hand the second paste and find with no arguments are equivalent.edit: screwed up benchmarks
NetBSD has had it for 11 years. FreeBSD has had it for three years and six months. DragonFly doesn't have it, OpenBSD doesn't have it...
http://cvsweb.netbsd.org/bsdweb.cgi/src/usr.bin/cal/cal.c?re... http://svnweb.freebsd.org/base?view=revision&revision=204697
> cal sep 1752
September 1752
Su Mo Tu We Th Fr Sa
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Edit: Oh, colour me surprised. https://en.wikipedia.org/wiki/September_14 % cal 2 1972 | tail +3 | wc -w
29What am I doing wrong?
This worked like a charm though:
cal dec 2002 | tail -6 | wc -w
(since it always takes up 6 lines, even sep 1752)
On older systems, the leading '-' can be replaced by '+' in the obsolete option syntax with the same meaning as in counts, and obsolete usage overrides normal usage when the two conflict. This obsolete behavior can be enabled or disabled with the '_POSIX2_VERSION' environment variable (*note Standards conformance::).Examples include: $ df -h | column -t $ column -t -s: /etc/passwd
For others who don't know it: http://en.wikipedia.org/wiki/Pushd_and_popd. It essentially is a stack for the working directory, so you can get back to where you were previously quickly and easily.
alias d='[ ${#DIRSTACK[@]} -gt 0 ] && for i in `jot ${#DIRSTACK[@]} 1 ${#DIRSTACK[@]} 1`; do echo ${DIRSTACK[$i-1]}; done; echo $PWD'
alias popd='[ ${#DIRSTACK[@]} -gt 0 ] && { cd "${DIRSTACK[${#DIRSTACK[@]}-1]}"; unset DIRSTACK[${#DIRSTACK[@]}-1]; }; d'
alias pushd='DIRSTACK[${#DIRSTACK[@]}]="$PWD"; cd'http://jeroenjanssens.com/2013/08/16/quickly-navigate-your-f...
imap jf <ESC>
was very nice as I find it much more ergonomic. And to use it in Bash I have
set editing-mode vi set keymap vi
$if mode=vi set keymap vi-insert "jf": vi-movement-mode $endif
set show-all-if-ambiguous on
column - columnify the incoming stream into columns
pr - set up incoming stream for pretty printing including columnification along or across the screen
tr - sanitize input, collapse several delimiters into one
echo $PATH | tr : '\n'
The advantage of using less here is that you can easily interrupt the tailing (ctrl-c). For example, to search. Then just hit 'F' again to restart tailing. But now your search pattern will be highlighted as the data streams by.
$ man xxd | grep vi
Use xxd as a filter within an editor such as vim(1) to hexdump a region
Use xxd as a filter within an editor such as vim(1) to recover a binary
Use xxd as a filter within an editor such as vim(1) to recover one line
http://grail.cba.csuohio.edu/~somos/xxd.cFrom what I've been able to find, vim was released in 1991, and xxd has been around since at least 1990, whereas vi was written by Bill Joy in 1976. (according to Wikipedia)
Interesting bit of trivia, perhaps someone with a good memory can clear it up for us?
I'm a bit more tolerant of vi now, but just because I "never" see it courtesy of suitable EDITOR entries.
At any password prompt, if you knowingly mis-keyed your password, rather than pressing return, getting the "your an idiot" message (often after an annoying 1 - 2 second delay), and having to retype the command, you can actually press ctrl-U, which is the "Clear the line" bash command, and start over typing your password again.
PS if you are a Vim user, you owe it to yourself to try the vim-style keybinds. They make a world of difference.
history | grep <keyword>
I use this for <keyword> rsync or rdesktop when I have forgotten the long list of options & directories etcI also use ctrl R <keyword> at the bash prompt but that only gives me the most recent match.
Are you sure, I'm using BASH on Kubuntu and I get previous matches by repeated use of ctrl+R.
Actually inspired by a previous post here I made a script "hs" that searches archived history files and shows me all past match lines. Before that I did what you do now.
set -o vi
it's awesomeThe ASCII table might be useful when you're dealing with encoding problems and want to know e.g. what exactly happened in a broken URL encoding. I used both of them for binary exploitation in the security class I took at university: When utilizing buffer overflows, it's important to get every byte at the right place of your payload. Sometimes, you also need to treat it as a string and that's where ASCII comes in.
These are only two specific usecases. As I said, there are a lot more. Development of binary file parsers could be another.
... and the best hint imo to process malformed filenames per 'find -print0' is:
find ... -print0 | { while read -d $'\0' fil ... # use variable fil }
Regards
Want to find all the tools on your system that use the curses library (for user-friendly interfaces)? Try this:
for i in `\ls /bin/* /sbin/* /usr/bin/* /usr/sbin/* | sort -u` ; do ldd $i 2>/dev/null | grep -q curses && whatis `basename $i` ; done | grep -v 'nothing appropriate'
Don't know how your current path finds a program? Use which: pwillis@zippy:~$ which df
/usr/bin/df
pwillis@zippy:~$ which mount
/bin/mount
Annoyed that /sbin and /usr/sbin aren't in your path? Use whereis: pwillis@zippy:~$ which ifconfig
which: no ifconfig in (/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/lib64/kde4/libexec:/usr/kerberos/bin:/usr/lib64/java/bin:/usr/lib64/java/jre/bin:/usr/lib64/qt/bin:/usr/share/texmf/bin:.)
pwillis@zippy:~$ whereis ifconfig
ifconfig: /sbin/ifconfig /usr/man/man8/ifconfig.8.gz /usr/share/man/man8/ifconfig.8.gz /usr/X11/man/man8/ifconfig.8.gz > where ls
ls: aliased to ls --color=tty
/usr/bin/ls
/bin/ls % type -a which
which is a shell builtin
which is /usr/bin/which
Convenient if you really want to know what you'll be calling. cp {file,.bak}
reduces to cp file file.bak cp file{,.bak}
Was it a typo, or is there some feature/special-case I don't know about?To connect to the shell from Windows, you can use the Putty program (google for it), although the shell documentation will almost certainly tell you how to do it.
1. Both are operating systems
2. Both are conceptually simple.
3. There is always nice command that does what you want but you somehow forget it. I can't believe that Common Lisp has just 900+ symbols but I routinely forget some of them when programming.
... I think it works when apropos isn't installed. Possibly it just calls out to it.
ISTR Forth had something similar, or maybe I'm just thinking that in Forth, words are almost uniquely defined by their stack annotations.