This post title sounds like a spam email subject but I was asked twice in the
past three weeks where I buy my t-shirts, so here’s an answer that everybody
can benefit from.
Living in Europe means we can get quite high shipping costs on US-based
websites. The highest shipping cost per t-shirt I ever got was $23 for two
t-shirts and on some websites up to 40% of the total cost is due to shipping.
The main criteria I have when buying t-shirts online are:
- Their price. I very rarely buy t-shirts that are more expensive than $20-25.
The reason is I like to buy multiple t-shirts at once and having to pay $100
for four t-shirts plus shipping isn’t something I’d consider.
- The quality of their design. Of course if all you want is a unicolor t-shirt
you can go to virtually any clothing store in the street to get one.
- Their shipping costs and how much time I’ll have to wait (spoiler: at the
very least a couple weeks if it comes from the US).
A bonus point is if they accept Paypal. This is because Paypal does the
Euro/Dollar conversion for me; otherwise if I pay with my credit card in
Dollars my bank steals takes me ~1% of the price, or €1 if it’s lower
than €100.
Not-that-fun story: I once had to pay a $0.02 AWS bill. It cost me €1.02; €1
for my bank and ~€0.02 for AWS.
Note that I’m not affiliated with any of the websites listed in this post and I
bought one or more times on each one.
Threadless
Threadless is the first website I ordered shirts
on; back in 2009. They have a large choice of t-shirts; you have to really dig
to find geeky ones. A lot of them are as low as $10-12 and they have promos
where shirts can go as low as $5. All the ones I bought in 2009 are still in
perfect condition. The shipping costs are acceptable at ~30% of the total cost
(e.g. 5 t-shirts for $45 + $27 for shipping = $72) but I need at least a month
to receive my package.
Pluses: Large choice, good prices.
Minuses: YMMV but I need to dig a lot to find t-shirts I like.
6 Dollar Shirts
I don’t remember how I found 6 Dollar Shirts but
it was quite a pleasant surprise to see a website that sells shirts at $6 each.
They even have a special price at $50 for ten of them. They have a lot more
geeky shirts and ones with references to popular culture. There are also a lot
of political t-shirts that I’m not interested in — but again you may like them.
The downside of the site are the high shipping costs: $35 for ten shirts. But
given their shirt prices it stays very low: $50+$35 for ten t-shirts means only
$8.5 per t-shirt. The first ones I bought in 2013 are still in pretty good
shape. They’re not as good as Threadless’ but they’re really good for their
price.
Pluses: Prices, and some designs are really great.
Minuses: After ~20 t-shirts I find it hard to find enough nice shirts to
fill another 10-shirts bulk.
Teespring
Teespring is a time-limited t-shirts website. People
submit their design and if there are enough buyers before a few days it goes to
print. It’s not a site I often go on but it seems to be popular for when people
want to print a special-occasion shirt.
I bought two shirts from them in 2014; each one cost $18 plus $12 of shipping
cost. That’s quite high, which is why I don’t often visit their website.
Pluses: Some shirts are nice.
Minuses: Prices are high and there’s not a lot of choice.
Cotton Bureau
Cotton Bureau is similar to Teespring but with
higher prices and goals appears to be higher than Teespring so less t-shirts go
to print. They do have nice shirts, thought.
Last time I bought a t-shirt from them was on October 31 of this year. I picked
a Mystery Tee as well, which is a cheaper shirt they choose for you. They
should ship on November 28 so I should get them for Christmas — That’s a long
time to wait. I paid $25 for the t-shirt I chose; $15 for the Mystery one; and
$24 for the shipping. You have to really want that t-shirt to pay that much.
Pluses: Nice designs and if enough people subscribe to an already-printed
t-shirt it goes to print again.
Minuses: Quite expensive and you have to wait until the end of the buying
window to have it printed and shipped.
Redbubble
Redbubble is a marketplace that sells a lot of
stuff with designs from a lot of people.
They have a lot of choice but in my experience the quality of their designs is
lower than Threadless’ and 6 Dollar Shirts’. They even sometimes have
duplicated or copied designs: two or three people got the same idea and
submitted (almost) the same design.
The positive side of this is you’ll often find t-shirts that refer to current
TV series that don’t have official stores (unlike CBS’ series), for example this Bojack-Horseman-themed shirt.
Their shipping costs are pretty low; I paid only €2.5 to get my €21 t-shirt.
Pluses: Low shipping costs and some nice finds if you search a lot.
Minuses: A lot of not-so-original designs that make it harder to find the
good ones.
TeeFury
TeeFury is a daily t-shirt website. They have two
shirts featured for a day at $11; otherwise you have to pay the full price
($20). I’m not a huge fan of their designs but they have very low shipping
costs; only $3 for a $11 t-shirt.
Pluses: They’re the cheapest option of this list when you buy only one or
two t-shirts at once.
Minuses: Only two t-shirts per day.
I hope this post may help you buy (cheap) t-shirts online. Note the shipping
costs I gave were for me in France; they may vary depending on your location.
Please share your own recommendations in the comments!
•

For a lot of people, the GNU tar command’s options seem obscure and hard to
use. The most common ones exist only in a short form and always appear grouped
in the same order and often without a leading hyphen, e.g. tar xzvf
archive.tgz and not tar -v -z -x -f archive.tgz. Additionally, tar doesn’t
work without any “option”.
These options, or rather these commands, can be seen as a (small) language that
you can learn to speak, write or read. Each command has its own
meaning that sometimes depend on which other commands are used with it.
The Grammar
tar’s sentences start with a verb. There’s no subject, because you’re giving
an order to tar. This verb is followed by zero or more modifiers that give
more context to the action. The last part is the object(s) on which the action
is made. Spaces are not needed between tar’s words because they all consist
of one letter.
Actions
The two most common actions are “create” (c) and “extract”
(x). The first one is used to create an archive from some files; and the
second is used to extract that archive in order to get back those files.
All tar implementations support one more action: “list” (t) to
list an archive’s content without extracting it. Some implementations support
two variants of “create” that are “append” (r) and “update”
(u). The former appends files to an existing archive; the latter updates
files in the archive for which there exist a more recent version.
Unfortunately we now know all tar actions but can’t do much without knowing
how to apply them to an object. Let’s dive into objects and we’ll see the
modifiers later.
Objects
tar has a very limited set of objects: archives. Each tar command operates
on one archive, that is given by f (for “file”) followed by its path.
Files added or extracted from archives are simply given as extra arguments to
these commands without needing any special word.
We’re now ready to write our first meaningful sentences.
“Hey tar, please create an archive file foo.tar with file1
and file2” is written as tar cf foo.tar file1 file2.
“Extract archive file foo.tar” is written as tar xf foo.tar.
“List archive file foo.tar” is written as tar tf foo.tar. You get
the idea.
Note that actions like “extract” or “list” accept additional
arguments for the file patterns you want to extract/list. Say you have a big
archive from which you only want to extract one important.txt file. Just give
this information to tar and it’ll kindly extract it for you:
tar xf big-archive.tar important.txt
You might wonder what is this “file” word for if we always need it.
Well, we can remove it. But if we do so, our tar command doesn’t have any
object left, so it’ll look at something else: STDIN or STDOUT.
Actions that read archives operate on STDIN if you don’t give them a
file object:
cat big-archive.tar | tar x important.txt
You can also be explicit by giving - to f:
cat big-archive.tar | tar xf - important.txt
The “create” action will output the archive on STDOUT if you don’t
give it a name (or use f -). You still need to give it the name of the files
to put in that archive:
tar c file1 file2 > archive.tar
# Same, but more explicit
tar cf - file1 file2 > archive.tar
Note that you can’t extract an archive to STDOUT without a modifier.
tar operates on files, not on data streams. By default it doesn’t compress
its content so creating a tar archive for one file doesn’t make much
sense.
Now that we know how to write basic sentences, let’s add some modifiers to
them.
Modifiers
In my experience the most used modifiers are v and z. The first one is the
“verbose” flag and makes tar more chatty. When creating or
extracting an archive it’ll print each file’s name as it’s (un)archiving
it. When listing an archive it’ll print more info about each file.
Compare both outputs below:
$ tar tf archive.tar
file1
file2
$ tar tvf archive.tar
-rw-r--r-- 0 baptiste wheel 31425 18 sep 14:51 file1
-rw-r--r-- 0 baptiste wheel 18410 18 sep 14:51 file2
The v modifier can be combined with any other one mentioned below.
z will tell tar to use Gzip to (de)compress the archive. Nowadays
tar-ing with no compression is rarely used, and Gzip is ubiquitous. Just add
z to your modifiers and tar will create compressed archive and
extract them. The convention is to use .tar.gz or .tgz for such
archives:
tar czf archive.tar.gz file1 file2
# Later…
tar xzf archive.tar.gz
Other common modifiers include j that works exactly like z but (de)compress
using Bzip2 instead of Gzip. Such archives usually end with .tar.bz2 or
.tbz2. It’s not named b or B because those were already taken when
this modifier was introduced.
Similarly to j one can use its capital friend, J. This one compresses using
xz instead of the last Gzip or Bzip2. These archives use the extensions
.tar.xz or .txz.
Note you can also (de)compress archives by yourself if you don’t remember these
modifiers:
tar cf myarchive.tar file1 file2
gzip myarchive.tar
# Later…
gunzip myarchive.tar
tar xf myarchive.tar
There is a dozen of other modifiers you can find in the manpage, but let’s
mention two more: O and k. You may remember from the first section that I
wrote you can’t extract an archive to STDOUT without a modifier. Well,
that modifier is called O:
Using O when extracting will print the content of the archive on
STDOUT. This is the same output as you would get by calling cat on all the
files in it.
The last modifier I wanted to mention is k, which tells tar not to override
existing files when extracting an archive. That is, if you already have
a file called important.txt in your directory and you un-tar an archive
using the k modifier, you can be sure it won’t override your existing
important.txt file.
I hope this post helped you have a better understanding of tar commands, and
how they’re not that complicated. I put a few (valid) commands below, just so
you can see if you understand what’s they’re doing:
tar xf foo.tar
tar cvzf bar.tar a b c
tar tvf foo.tar important.txt
tar cz file1 file2 > somefile
tar xzOf somefile
tar cJf hey.txz you andyou
tar xkjvf onemore.tbz2
•
This is the first post of a serie I’m starting about syntax quirks in various
languages. I’ll divide each post in two parts: the first one states the
question (mainly “Is this valid? What does it do? How does it work?”); the
second one gives an answer.
In Ruby, any sequence of 3+4n (where n≥0) percent signs (%) is valid;
can you guess why?
Here are the first members of this suite:
%%% # n=0
%%%%%%% # n=1
%%%%%%%%%%% # n=2
%%%%%%%%%%%%%%% # n=3
I’m using Ruby 2.3.0 but this I was able to test this behavior on the
almost-10-years-old Ruby 1.8.5, so you should be fine with any version.
You can stop here and try to solve this problem or skip below for an answer.
The answer to the problem lies in two things: string literals and string
formatting.
You might know you can use %q() to create a string; which can be handy if you
have both single and double quotes and don’t want to escape them:
my_str = %q(it's a "valid" string)
This method doesn’t support interpolation with #{} but its uppercased friend
does:
my_str = %Q(i's still #{42 - 41} "valid" string)
The equivalent also exists to create arrays of strings with %w() and
%W(), regular expressions with %r, as well as %i to create arrays of
symbols starting in Ruby 2.0.0:
names = %w(alice bob charlie) # => ["alice", "bob", "charlie"]
names.each { |name| puts "Hello #{name}" }
my_syms = %i(my symbols) # => [:my, :symbols]
puts "yep" if %q(my string) =~ %r(my.+regexp)
You can also use [],{} or <> instead of parentheses:
%w{foo bar} # => ["foo", "bar"]
%q[my string goes here] # => "my string goes here"
%i<a b c> # => [:a, :b, :c]
Ruby lets you use a percent sign alone as an alias of %Q:
%(foo bar) == %<foo bar> # => true
%{foo bar} == "foo bar" # => true
But wait; there’s more! You can also use most non-alphanumeric characters like
| (%|my string|), ^ (%w^x y z^), or… %:
%w%my array% # => ["my", "array"]
%q%my string% # => "my string"
%%my other string% # => "my other string"
This means that %||, %^^ or %%% can be used to denote an empty string
(don’t do that in real programs, please). It answers the problem for the case
n=0: %%% is an empty string; the first percent sign indicates it’s a literal
string, and the following two are respectively the beginning and end
delimiters.
The second part of our answer is string formatting.
If you have ever written a Python program you know it supports string
formatting à la sprintf with %:
print "this is %s, I'm %d years-old" % ("Python", 25)
Well, Ruby supports the same method, called String#%:
puts "this is %s, I'm %d years-old" % ["Ruby", 21]
In both languages you can drop the array/tuple if you have only one argument:
print "I'm %s" % "Python"
print "I'm %d" % 25
puts "I'm %s" % "Ruby"
puts "I'm %d" % 21
Both will raise an exception if you have not enough arguments but only Python
will do it if you have too many of them:
# Python
print "I'm %s" % ["Python", "Ruby"]
# => TypeError: not all arguments converted during string formatting
# Ruby
puts "I'm %s" % ["Ruby", "Python"]
# prints "I'm Ruby"
This means that while "" % "" is syntaxically valid in both languages, only
Ruby runs it without error, because Python raises an exception telling that the
argument (the string on the right) is not used.
If we combine this knowledge with what we have above with literal strings we
now know we can write the following in Ruby:
%%% % %%% # equivalent to "" % ""
The last key is that it works without spaces and can be chained:
"" % "" % "" # => ""
%%% % %%% % %%% # => ""
%%%%%%%%%%% # => ""
The 3+4n refers to the way the expression is constructed: the first three
percent signs are an empty string, and the next four ones are the formatting
operator followed by another empty string.
Want more of these? Here are a few other valid Ruby expressions using strings
and percent signs (one per line); guess how they’re parsed and evaluated:
%*%%*%%*%%*
%_/\|/\_/\|/\__
%_.-''-._%%_.-''-._%%_.-''-_%%.etc.
%/\/\/\/\/\______/
%# <- is it really valid? :-#
•