From 9140d2ebfb878615fc49bfa223c5cd3b79f31805 Mon Sep 17 00:00:00 2001 From: Lars Yencken Date: Wed, 21 Aug 2013 16:35:39 +1000 Subject: [PATCH 1/6] Allow suffixes for cheat files (e.g. DataFrames.jl). --- cheat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheat b/cheat index e49c0ce..8ddd7b8 100755 --- a/cheat +++ b/cheat @@ -23,7 +23,7 @@ def cheat_files(cheat_directories): cheats = {} for cheat_dir in reversed(cheat_directories): cheats.update(dict([ (cheat, cheat_dir)\ - for cheat in os.listdir(cheat_dir) if '.' not in cheat ])) + for cheat in os.listdir(cheat_dir) if not cheat.startswith('.')])) return cheats def main(): From 17b2148d6ea3d3c69a6049353db41965ec5552b6 Mon Sep 17 00:00:00 2001 From: Lars Yencken Date: Wed, 21 Aug 2013 16:46:10 +1000 Subject: [PATCH 2/6] Reformat to meet PEP8 style. --- cheat | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/cheat b/cheat index 8ddd7b8..af4e153 100755 --- a/cheat +++ b/cheat @@ -2,8 +2,9 @@ import os import sys -# assembles a list of directories containing cheatsheets + def cheat_directories(): + "Assembles a list of directories containing cheatsheets." default_directories = [os.path.expanduser('~/.cheat')] try: import cheatsheets @@ -11,32 +12,35 @@ def cheat_directories(): except ImportError: pass - default = [ default_dir for default_dir in default_directories if os.path.isdir(default_dir) ] + default = [default_dir for default_dir in default_directories + if os.path.isdir(default_dir)] + if 'CHEATPATH' in os.environ and os.environ['CHEATPATH']: - return [ path for path in os.environ['CHEATPATH'].split(os.pathsep)\ - if os.path.isdir(path) ] + default + return [path for path in os.environ['CHEATPATH'].split(os.pathsep) + if os.path.isdir(path)] + default else: return default -# assembles a dictionary of cheatsheets found in the above directories + def cheat_files(cheat_directories): + "Assembles a dictionary of cheatsheets found in the above directories." cheats = {} for cheat_dir in reversed(cheat_directories): - cheats.update(dict([ (cheat, cheat_dir)\ - for cheat in os.listdir(cheat_dir) if not cheat.startswith('.')])) + cheats.update(dict([(cheat, cheat_dir) + for cheat in os.listdir(cheat_dir) + if not cheat.startswith('.')])) return cheats -def main(): - """MAIN""" +def main(): # assemble a keyphrase out of all params passed to the script - keyphrase = ' '.join(sys.argv[1:]) + keyphrase = ' '.join(sys.argv[1:]) cheat_dirs = cheat_directories() # verify that we have at least one cheat directory if not cheat_dirs: - print >> sys.stderr, \ - 'The ~/.cheat dir does not exist or the CHEATPATH var is not set.' + print >> sys.stderr, ('The ~/.cheat dir does not exist or the ' + 'CHEATPATH var is not set.') exit() # list the files in the ~/.cheat directory @@ -46,20 +50,21 @@ def main(): if keyphrase.lower() in ['', 'cheat', 'help', '-h', '-help', '--help']: print "Usage: cheat [keyphrase]\n" print "Available keyphrases:" - max_command = max([ len(x) for x in cheatsheets.keys() ]) + 3 - print '\n'.join(sorted([ '%s [%s]' % (key.ljust(max_command), value)\ - for key, value in cheatsheets.items() ])) + max_command = max([len(x) for x in cheatsheets.keys()]) + 3 + print '\n'.join(sorted(['%s [%s]' % (key.ljust(max_command), value) + for key, value in cheatsheets.items()])) exit() # print the cheatsheet if it exists if keyphrase in cheatsheets: - with open (os.path.join(cheatsheets[keyphrase], keyphrase), 'r')\ - as cheatsheet: + filename = os.path.join(cheatsheets[keyphrase], keyphrase) + with open(filename, 'r') as cheatsheet: print cheatsheet.read() # if it does not, say so else: print 'No cheatsheet found for %s.' % keyphrase + if __name__ == '__main__': main() From c6bb350a13809c6a60175b11226fc889344c8634 Mon Sep 17 00:00:00 2001 From: Lars Yencken Date: Wed, 21 Aug 2013 17:00:24 +1000 Subject: [PATCH 3/6] Colorize output using Pygment lexers. --- cheat | 26 ++++++++++++++++++++++++-- setup.py | 3 ++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/cheat b/cheat index af4e153..2f5062d 100755 --- a/cheat +++ b/cheat @@ -2,6 +2,11 @@ import os import sys +from pygments import highlight +from pygments.util import ClassNotFound +from pygments.lexers import get_lexer_for_filename, TextLexer +from pygments.formatters import TerminalFormatter + def cheat_directories(): "Assembles a list of directories containing cheatsheets." @@ -58,13 +63,30 @@ def main(): # print the cheatsheet if it exists if keyphrase in cheatsheets: filename = os.path.join(cheatsheets[keyphrase], keyphrase) - with open(filename, 'r') as cheatsheet: - print cheatsheet.read() + pretty_print(filename) # if it does not, say so else: print 'No cheatsheet found for %s.' % keyphrase +def pretty_print(filename): + try: + if os.path.splitext(filename)[1]: + lexer = get_lexer_for_filename(filename) + else: + # shell is a sensible default when there is no extension + lexer = get_lexer_for_filename(filename + '.sh') + + except ClassNotFound: + lexer = TextLexer() + + with open(filename) as istream: + code = istream.read() + + fmt = TerminalFormatter() + highlight(code, lexer, fmt, sys.stdout) + + if __name__ == '__main__': main() diff --git a/setup.py b/setup.py index af240f9..4b10199 100644 --- a/setup.py +++ b/setup.py @@ -5,12 +5,13 @@ import os setup(name='cheat', version='1.0', - description='Create and view interactive cheatsheets on the command-line', + description='Create and view interactive cheatsheets on the command-line', # nopep8 author='Chris Lane', author_email='chris@chris-allen-lane.com', url='https://github.com/chrisallenlane/cheat', packages=['cheatsheets'], package_data={'cheatsheets': [f for f in os.listdir('cheatsheets') if '.' not in f]}, + install_requires=['Pygments>=1.6'], scripts=['cheat'] ) From 39a15a669a2997c0b2bbd89dae943b5341dcf0fa Mon Sep 17 00:00:00 2001 From: Lars Yencken Date: Wed, 21 Aug 2013 19:33:09 +1000 Subject: [PATCH 4/6] Make Pygments a soft dependency. --- cheat | 19 ++++++++++++++----- setup.py | 1 - 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cheat b/cheat index 2f5062d..9f78aaa 100755 --- a/cheat +++ b/cheat @@ -2,10 +2,14 @@ import os import sys -from pygments import highlight -from pygments.util import ClassNotFound -from pygments.lexers import get_lexer_for_filename, TextLexer -from pygments.formatters import TerminalFormatter +try: + from pygments import highlight + from pygments.util import ClassNotFound + from pygments.lexers import get_lexer_for_filename, TextLexer + from pygments.formatters import TerminalFormatter + USE_PYGMENTS = True +except ImportError: + USE_PYGMENTS = False def cheat_directories(): @@ -63,7 +67,12 @@ def main(): # print the cheatsheet if it exists if keyphrase in cheatsheets: filename = os.path.join(cheatsheets[keyphrase], keyphrase) - pretty_print(filename) + if USE_PYGMENTS: + pretty_print(filename) + else: + with open(filename) as istream: + for l in istream: + sys.stdout.write(l) # if it does not, say so else: diff --git a/setup.py b/setup.py index 4b10199..f4fd1c8 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,5 @@ setup(name='cheat', packages=['cheatsheets'], package_data={'cheatsheets': [f for f in os.listdir('cheatsheets') if '.' not in f]}, - install_requires=['Pygments>=1.6'], scripts=['cheat'] ) From f89d887c21a0e0e2ed176add94db134877f13b8b Mon Sep 17 00:00:00 2001 From: Lars Yencken Date: Thu, 22 Aug 2013 09:19:31 +1000 Subject: [PATCH 5/6] Add a check for posix environment for pygments. --- cheat | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/cheat b/cheat index 9f78aaa..210c251 100755 --- a/cheat +++ b/cheat @@ -2,14 +2,18 @@ import os import sys -try: - from pygments import highlight - from pygments.util import ClassNotFound - from pygments.lexers import get_lexer_for_filename, TextLexer - from pygments.formatters import TerminalFormatter - USE_PYGMENTS = True -except ImportError: - USE_PYGMENTS = False +USE_PYGMENTS = False + +# NOTE remove this check if it is confirmed to work on windows +if os.name == 'posix': + try: + from pygments import highlight + from pygments.util import ClassNotFound + from pygments.lexers import get_lexer_for_filename, TextLexer + from pygments.formatters import TerminalFormatter + USE_PYGMENTS = True + except ImportError: + pass def cheat_directories(): From 8245d3f4ec5be642e6e2258f018fd0eecf51a48c Mon Sep 17 00:00:00 2001 From: Lars Yencken Date: Thu, 22 Aug 2013 11:34:11 +1000 Subject: [PATCH 6/6] Explicitly mark comment lines in builtin sheets. --- cheatsheets/apt-cache | 2 +- cheatsheets/asterisk | 12 ++++++------ cheatsheets/bash | 4 ++-- cheatsheets/convert | 12 ++++++------ cheatsheets/cut | 2 +- cheatsheets/dhclient | 6 +++--- cheatsheets/find | 10 +++++----- cheatsheets/git | 4 ++-- cheatsheets/ln | 2 +- cheatsheets/mysqldump | 6 +++--- cheatsheets/netstat | 2 +- cheatsheets/nmap | 30 +++++++++++++++--------------- cheatsheets/notify-send | 4 ++-- cheatsheets/openssl | 8 ++++---- cheatsheets/scp | 6 +++--- cheatsheets/sed | 6 +++--- cheatsheets/shred | 10 +++++----- cheatsheets/sockstat | 2 +- cheatsheets/split | 6 +++--- cheatsheets/ssh | 10 +++++----- cheatsheets/ssh-copy-id | 4 ++-- cheatsheets/ssh-keygen | 8 ++++---- cheatsheets/stdout | 4 ++-- cheatsheets/tar | 12 ++++++------ 24 files changed, 86 insertions(+), 86 deletions(-) diff --git a/cheatsheets/apt-cache b/cheatsheets/apt-cache index 9a0e02b..933212b 100644 --- a/cheatsheets/apt-cache +++ b/cheatsheets/apt-cache @@ -1,2 +1,2 @@ -To search for apt packages: +# To search for apt packages: apt-cache search "whatever" diff --git a/cheatsheets/asterisk b/cheatsheets/asterisk index f0cf107..df2c02b 100644 --- a/cheatsheets/asterisk +++ b/cheatsheets/asterisk @@ -1,17 +1,17 @@ -To connect to a running Asterisk session: +# To connect to a running Asterisk session: asterisk -rvvv -To issue a command to Asterisk from the shell: +# To issue a command to Asterisk from the shell: asterisk -rx "" -To originate an echo call from a SIP trunk on an Asterisk server, to a specified number: +# To originate an echo call from a SIP trunk on an Asterisk server, to a specified number: asterisk -rx "channel originate SIP// application echo" -To print out the details of SIP accounts: +# To print out the details of SIP accounts: asterisk -rx "sip show peers" -To print out the passwords of SIP accounts: +# To print out the passwords of SIP accounts: asterisk -rx "sip show users" -To print out the current active channels: +# To print out the current active channels: asterisk -rx "core show channels" diff --git a/cheatsheets/bash b/cheatsheets/bash index 1d024ca..340158e 100644 --- a/cheatsheets/bash +++ b/cheatsheets/bash @@ -1,10 +1,10 @@ -To implement a for loop: +# To implement a for loop: for file in `ls .`; do echo 'file'; echo 'found'; done -To implement a case command: +# To implement a case command: case "$1" in 0) echo "zero found";; diff --git a/cheatsheets/convert b/cheatsheets/convert index 25bc8ed..20dbef0 100644 --- a/cheatsheets/convert +++ b/cheatsheets/convert @@ -1,17 +1,17 @@ -To resize an image to a fixed width and proportional height: +# To resize an image to a fixed width and proportional height: convert original-image.jpg -resize 100x converted-image.jpg -To resize an image to a fixed height and proportional width: +# To resize an image to a fixed height and proportional width: convert original-image.jpg -resize x100 converted-image.jpg -To resize an image to a fixed width and height: +# To resize an image to a fixed width and height: convert original-image.jpg -resize 100x100 converted-image.jpg -To resize an image and simultaneously change its file type: +# To resize an image and simultaneously change its file type: convert original-image.jpg -resize 100x converted-image.png -To resize all of the images within a directory: -To implement a for loop: +# To resize all of the images within a directory: +# To implement a for loop: for file in `ls original/image/path/`; do new_path=${file%.*}; new_file=`basename $new_path`; diff --git a/cheatsheets/cut b/cheatsheets/cut index 442aa39..1e7939f 100644 --- a/cheatsheets/cut +++ b/cheatsheets/cut @@ -1,2 +1,2 @@ -To cut out the third field of text or stdoutput that is delimited by a #: +# To cut out the third field of text or stdoutput that is delimited by a #: cut -d# -f3 diff --git a/cheatsheets/dhclient b/cheatsheets/dhclient index 6ac0750..028530e 100644 --- a/cheatsheets/dhclient +++ b/cheatsheets/dhclient @@ -1,7 +1,7 @@ -To release the current IP address: +# To release the current IP address: sudo dhclient -r -To obtain a new IP address: +# To obtain a new IP address: sudo dhclient -Running the above in sequence is a common way of refreshing an IP. +# Running the above in sequence is a common way of refreshing an IP. diff --git a/cheatsheets/find b/cheatsheets/find index 0e99e3c..a78583a 100644 --- a/cheatsheets/find +++ b/cheatsheets/find @@ -1,14 +1,14 @@ -To find files by extension (ex: .jpg): +# To find files by extension (ex: .jpg): find . -iname "*.jpg" -To find directories: +# To find directories: find . -type d -To find files: +# To find files: find . -type f -To find files by octal permission: +# To find files by octal permission: find . -type f -perm 777 -To find files with setuid bit set: +# To find files with setuid bit set: find . -xdev \( -perm -4000 \) -type f -print0 | xargs -0 ls -l diff --git a/cheatsheets/git b/cheatsheets/git index efba67e..ddb7946 100644 --- a/cheatsheets/git +++ b/cheatsheets/git @@ -1,6 +1,6 @@ -To set your identify: +# To set your identify: git config --global user.name "John Doe" git config --global user.email johndoe@example.com -To enable color: +# To enable color: git config --global color.ui true diff --git a/cheatsheets/ln b/cheatsheets/ln index ab95c66..441c3a9 100644 --- a/cheatsheets/ln +++ b/cheatsheets/ln @@ -1,2 +1,2 @@ -To create a symlink: +# To create a symlink: ln -s path/to/the/target/directory name-of-symlink diff --git a/cheatsheets/mysqldump b/cheatsheets/mysqldump index 0b22002..7652efa 100644 --- a/cheatsheets/mysqldump +++ b/cheatsheets/mysqldump @@ -1,8 +1,8 @@ -To dump a database to a file: +# To dump a database to a file: mysqldump -uusername -ppassword the-database > db.sql -To dump a database to a .tgz file: +# To dump a database to a .tgz file: mysqldump -uusername -ppassword the-database | gzip -9 > db.sql -To dump all databases to a file: +# To dump all databases to a file: mysqldump -uusername -ppassword --all-databases > all-databases.sql diff --git a/cheatsheets/netstat b/cheatsheets/netstat index 863788b..dbf6ae4 100644 --- a/cheatsheets/netstat +++ b/cheatsheets/netstat @@ -1,2 +1,2 @@ -To view which users/processes are listening to which ports: +# To view which users/processes are listening to which ports: sudo netstat -lnptu diff --git a/cheatsheets/nmap b/cheatsheets/nmap index 61c58c6..7620afd 100644 --- a/cheatsheets/nmap +++ b/cheatsheets/nmap @@ -1,33 +1,33 @@ -Single target scan: +# Single target scan: nmap [target] -Scan from a list of targets: +# Scan from a list of targets: nmap -iL [list.txt] -iPv6: +# iPv6: nmap -6 [target] -OS detection: +# OS detection: nmap -O [target] -Save output to text file: +# Save output to text file: nmap -oN [output.txt] [target] -Save output to xml file: +# Save output to xml file: nmap -oX [output.xml] [target] -Scan a specific port: +# Scan a specific port: nmap -source-port [port] [target] -Do an aggressive scan: +# Do an aggressive scan: nmap -A [target] -Traceroute: +# Traceroute: nmap -traceroute [target] -Ping scan only: -sP -Don't ping: -PN -TCP SYN ping: -PS -TCP ACK ping: -PA -UDP ping: -PU -ARP ping: -PR +# Ping scan only: -sP +# Don't ping: -PN +# TCP SYN ping: -PS +# TCP ACK ping: -PA +# UDP ping: -PU +# ARP ping: -PR diff --git a/cheatsheets/notify-send b/cheatsheets/notify-send index 2722f67..6516064 100644 --- a/cheatsheets/notify-send +++ b/cheatsheets/notify-send @@ -1,4 +1,4 @@ -To send a desktop notification via dbus: +# To send a desktop notification via dbus: notify-send -i 'icon-file/name' -a 'application_name' 'summary' 'body of message' -The -i and -a flags can be omitted if unneeded. +# The -i and -a flags can be omitted if unneeded. diff --git a/cheatsheets/openssl b/cheatsheets/openssl index 9c47806..936d953 100644 --- a/cheatsheets/openssl +++ b/cheatsheets/openssl @@ -1,10 +1,10 @@ -To create a 2048-bit private key: +# To create a 2048-bit private key: openssl genrsa -out server.key 2048 -To create the Certificate Signing Request (CSR): +# To create the Certificate Signing Request (CSR): openssl req -new -key server.key -out server.csr -To sign a certificate using a private key and CSR: +# To sign a certificate using a private key and CSR: openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt -(The above commands may be run in sequence to generate a self-signed SSL certificate.) +# (The above commands may be run in sequence to generate a self-signed SSL certificate.) diff --git a/cheatsheets/scp b/cheatsheets/scp index abb8176..5b5ade9 100644 --- a/cheatsheets/scp +++ b/cheatsheets/scp @@ -1,5 +1,5 @@ -To copy a file from your local machine to a remote server: +# To copy a file from your local machine to a remote server: scp foo.txt user@example.com:remote/dir -To copy a file from a remote server to your local machine: -scp user@example.com:remote/dir/foo.txt local/dir \ No newline at end of file +# To copy a file from a remote server to your local machine: +scp user@example.com:remote/dir/foo.txt local/dir diff --git a/cheatsheets/sed b/cheatsheets/sed index 2707d7c..3b19720 100644 --- a/cheatsheets/sed +++ b/cheatsheets/sed @@ -1,8 +1,8 @@ -To replace all occurrences of "day" with "night" and write to stdout: +# To replace all occurrences of "day" with "night" and write to stdout: sed s/day/night file.txt -To replace all occurrences of "day" with "night" within file.txt: +# To replace all occurrences of "day" with "night" within file.txt: sed s/day/night file.txt > file.txt -To replace all occurrences of "day" with "night" on stdin: +# To replace all occurrences of "day" with "night" on stdin: echo 'It is daytime' | sed s/day/night/ diff --git a/cheatsheets/shred b/cheatsheets/shred index 3aa3300..3962082 100644 --- a/cheatsheets/shred +++ b/cheatsheets/shred @@ -1,13 +1,13 @@ -To shred a file (5 passes) and verbose output: +# To shred a file (5 passes) and verbose output: shred -n 5 -v file.txt -To shred a file (5 passes) and a final overwrite of zeroes: +# To shred a file (5 passes) and a final overwrite of zeroes: shred -n 5 -vz file.txt -To do the above, and then truncate and rm the file: +# To do the above, and then truncate and rm the file: shred -n 5 -vzu file.txt -To shred a partition: +# To shred a partition: shred -n 5 -vz /dev/sda -Remember that shred may not behave as expected on journaled file systems if file data is being journaled. +# Remember that shred may not behave as expected on journaled file systems if file data is being journaled. diff --git a/cheatsheets/sockstat b/cheatsheets/sockstat index cff34e2..21594fd 100644 --- a/cheatsheets/sockstat +++ b/cheatsheets/sockstat @@ -1,2 +1,2 @@ -To view which users/processes are listening to which ports: +# To view which users/processes are listening to which ports: sudo sockstat -l diff --git a/cheatsheets/split b/cheatsheets/split index 62a9427..8ffd1f3 100644 --- a/cheatsheets/split +++ b/cheatsheets/split @@ -1,8 +1,8 @@ -To split a large text file into smaller files of 1000 lines each: +# To split a large text file into smaller files of 1000 lines each: split file.txt -l 1000 -To split a large binary file into smaller files of 10M each: +# To split a large binary file into smaller files of 10M each: split file.txt -b 10M -To consolidate split files into a single file: +# To consolidate split files into a single file: cat x* > file.txt diff --git a/cheatsheets/ssh b/cheatsheets/ssh index 6099196..72681d7 100644 --- a/cheatsheets/ssh +++ b/cheatsheets/ssh @@ -1,11 +1,11 @@ -To execute a command on a remote server: +# To execute a command on a remote server: ssh -t user@example.com 'the-remote-command' -To tunnel an x session over SSH: +# To tunnel an x session over SSH: ssh -X user@example.com -To launch a specific x application over SSH: +# To launch a specific x application over SSH: ssh -X -t user@example.com 'chromium-browser' -For more information, see: -http://unix.stackexchange.com/q/12755/44856 +# For more information, see: +# http://unix.stackexchange.com/q/12755/44856 diff --git a/cheatsheets/ssh-copy-id b/cheatsheets/ssh-copy-id index 1a241b7..217479c 100644 --- a/cheatsheets/ssh-copy-id +++ b/cheatsheets/ssh-copy-id @@ -1,5 +1,5 @@ -To copy a key to a remote host: +# To copy a key to a remote host: ssh-copy-id username@host -To copy a key to a remote host on a non-standard port: +# To copy a key to a remote host on a non-standard port: ssh-copy-id username@host -p 2222 diff --git a/cheatsheets/ssh-keygen b/cheatsheets/ssh-keygen index 32986ba..5d9266d 100644 --- a/cheatsheets/ssh-keygen +++ b/cheatsheets/ssh-keygen @@ -1,11 +1,11 @@ -To generate an SSH key: +# To generate an SSH key: ssh-keygen -t rsa -To generate a 4096-bit SSH key: +# To generate a 4096-bit SSH key: ssh-keygen -t rsa -b 4096 -To copy a key to a remote host: +# To copy a key to a remote host: ssh-copy-id username@host -To copy a key to a remote host on a non-standard port: +# To copy a key to a remote host on a non-standard port: ssh-copy-id username@host -p 2222 diff --git a/cheatsheets/stdout b/cheatsheets/stdout index e1a8f57..bff788a 100644 --- a/cheatsheets/stdout +++ b/cheatsheets/stdout @@ -1,5 +1,5 @@ -To redirect stderr to stdout: +# To redirect stderr to stdout: some-command 2>&1 -To redirect stderr to a file +# To redirect stderr to a file some-command 2> errors.txt diff --git a/cheatsheets/tar b/cheatsheets/tar index a0f7a41..ab082db 100644 --- a/cheatsheets/tar +++ b/cheatsheets/tar @@ -1,17 +1,17 @@ -To extract an uncompressed archive: +# To extract an uncompressed archive: tar -xvf /path/to/foo.tar -To create an uncompressed archive: +# To create an uncompressed archive: tar -cvf /path/to/foo.tar /path/to/foo/ -To extract a .gz archive: +# To extract a .gz archive: tar -xzvf /path/to/foo.tgz -To create a .gz archive: +# To create a .gz archive: tar -czvf /path/to/foo.tgz /path/to/foo/ -To extract a .bz2 archive: +# To extract a .bz2 archive: tar -xjvf /path/to/foo.tgz -To create a .bz2 archive: +# To create a .bz2 archive: tar -cjvf /path/to/foo.tgz /path/to/foo/