4
\$\begingroup\$

The mission is to implement a cat-like program (copy all STDIN to STDOUT).

Rules:

  • You may only use standard libraries
  • Indentation must be either two spaces or a single tab (in languages which require indentation)
  • Scripts must use shebangs
  • The result of cat anything.txt | ./yourprogram | diff anything.txt - should be nothing and should not be an infinite loop

Go example (84 bytes)

package main
import (
  "os"
  "io"
)
func main() {
  io.Copy(os.Stdout,os.Stdin)
} 

C++ example (78 bytes)

#include<iostream>
using namespace std;
int main() {
  cout << cin.rdbuf();
}

Ruby example (44 bytes)

#!/usr/bin/env ruby
$stdout << $stdin.read

Shortest code (by bytes) wins.

\$\endgroup\$
24
  • 55
    \$\begingroup\$ This indentation thing is nonsense \$\endgroup\$
    – edc65
    Jun 15, 2014 at 12:49
  • 14
    \$\begingroup\$ The indentation rule doesn't make sense, the shebang one makes even less, because shebangs can be platform-specific, especially in the case of Python. \$\endgroup\$ Jun 15, 2014 at 14:50
  • 9
    \$\begingroup\$ until end of June 2914… Woaah… \$\endgroup\$
    – Qeole
    Jun 15, 2014 at 18:03
  • 7
    \$\begingroup\$ Also, person with most implementation? What? \$\endgroup\$ Jun 15, 2014 at 18:50
  • 4
    \$\begingroup\$ what about this python solution? for s in' /\___/\|( o o )|/ * \|\__\_/__/meow| / \| / ___ \| \/___\/'.split('|'):print s \$\endgroup\$
    – Willem
    Jul 4, 2014 at 15:50

37 Answers 37

44
\$\begingroup\$

GolfScript, 0 characters / bytes

This could technically be considered invalid since GolfScript will append a \n, but that can be fixed with :n; (3 bytes).

\$\endgroup\$
4
  • 6
    \$\begingroup\$ Haha, +1. Explanation for people who don't speak golfscript: stdin is read to the stack when the program starts and the stack is outputted when it ends. \$\endgroup\$
    – seequ
    Jun 15, 2014 at 12:47
  • 2
    \$\begingroup\$ Nice idea, but invalid. GolfScript will append a linefeed to the input. \$\endgroup\$
    – Dennis
    Jun 15, 2014 at 13:55
  • 1
    \$\begingroup\$ @Dennis That could be fixed in 3 bytes: :n; (edited) \$\endgroup\$
    – Doorknob
    Jun 15, 2014 at 14:11
  • 4
    \$\begingroup\$ I would say then that the zero-char solution is, unfortunately, invalid, and therefore the score is a solid 3. +1 nonetheless! \$\endgroup\$
    – Jwosty
    Jun 16, 2014 at 4:56
24
\$\begingroup\$

sed - 0 bytes

No command needed to cat a file with sed: all lines of input are printed without modification, so

sed ''

will act like cat for standard input, and

sed '' /etc/fstab

will print content of file.

\$\endgroup\$
2
  • \$\begingroup\$ "sed n" works for me and is one byte shorter. \$\endgroup\$ Aug 5, 2014 at 18:04
  • \$\begingroup\$ @GlennRanders-Pehrson Yes, thank you. I didn't count the quotes as part of the sed script (I considered an empty script, something similar to sed -f /dev/null input). If we are to count chars on the line, your proposal saves a byte indeed. \$\endgroup\$
    – Qeole
    Aug 5, 2014 at 20:54
19
\$\begingroup\$

ΒrainFuck (5 bytes)

,[.,]

Explanation:

,  Read first byte of input and place on stack
[  While top byte is not 0...
 . Print top byte from stack as ASCII and remove
 , Read next byte of input and place on stack
]  ...loop
\$\endgroup\$
5
  • 4
    \$\begingroup\$ one of those few tasks where BF is shorter than most other things... \$\endgroup\$
    – user16402
    Jun 20, 2014 at 19:54
  • \$\begingroup\$ This is less than 2 bytes (each command is 3 bits... totaling 15 bits). \$\endgroup\$
    – Timtech
    Jun 23, 2014 at 23:01
  • 2
    \$\begingroup\$ It is not 3 bits when stored in ASCII format, and I wrote it as ASCII. \$\endgroup\$
    – kitcar2000
    Jun 24, 2014 at 14:35
  • \$\begingroup\$ This will fail on files with a null in them though.. \$\endgroup\$
    – Claudiu
    Sep 10, 2014 at 20:46
  • \$\begingroup\$ @Claudiu how else would you tell when the file ends? This is BF :P \$\endgroup\$
    – clapp
    Dec 4, 2015 at 16:28
16
\$\begingroup\$

Haskell - 17 bytes

main=interact id

id is the identity function and from the documentation :

The interact function takes a function of type String->String as its argument. The entire input from the standard input device is passed to this function as its argument, and the resulting string is output on the standard output device.

\$\endgroup\$
10
\$\begingroup\$

x86_64 NASM Assembly for Linux - 125 / 100

r:mov ax,0
mov di,0
mov rsi,c
mov dx,1
syscall
cmp ax,0
je e
mov di,1
syscall
jg r
e:mov ax,60
syscall
SECTION .bss
c:resw 1

I couldn't get it to fit in 100 bytes, but it is assembly. Eight bytes could be saved at the cost of changing the return status to 1 instead of 0:

r:mov ax,0
mov di,0
mov rsi,c
mov dx,1
syscall
cmp ax,0
mov di,1
jg s
mov ax,60
s:syscall
jg r
SECTION .bss
c:resw 1

Now, if you really want 100 bytes, here is one in exactly 100 bytes. The problem is that it doesn't exit correctly, it just segfaults:

r:mov ax,0
mov di,0
mov rsi,c
mov dx,1
syscall
cmp ax,0
mov di,1
syscall
jg r
SECTION .bss
c:resw 1

The instructions say to only use standard libraries; is there extra credit for using no libraries at all?

\$\endgroup\$
0
6
\$\begingroup\$

C 43

main(c){while((c=getchar())>=0)putchar(c);}
\$\endgroup\$
6
  • 3
    \$\begingroup\$ You can use ~(c=getchar()) instead of (c=getchar())>=0 to save 2 characters. \$\endgroup\$ Jun 15, 2014 at 13:59
  • 1
    \$\begingroup\$ @nyuszika7h: EOF is typically -1, but this is not guaranteed by the standard. The standard only defines about EOF in section 7.19.1: EOF which expands to an integer constant expression, with type int and a negative value, that is returned by several functions to indicate end-of-file, that is, no more input from a stream; \$\endgroup\$
    – edc65
    Jun 15, 2014 at 16:11
  • \$\begingroup\$ main(){for(;putchar(getchar())<127;);} what's with that? (apparently putchar's return value is casted to int so EOF becomes 255) \$\endgroup\$
    – bebe
    Jun 18, 2014 at 17:54
  • \$\begingroup\$ @bebe yes it's pity. putchar get an int but truncates it to 8 bits. (It's in the spec) \$\endgroup\$
    – edc65
    Jun 18, 2014 at 18:35
  • \$\begingroup\$ @edc65 VC++ error C2065: 'c':undeclared identifier. Yes, sorry my comment about putchar was incorrect. \$\endgroup\$ Jun 23, 2014 at 19:43
5
\$\begingroup\$

Node.js 55

#!/usr/bin/env node
process.stdin.pipe(process.stdout);
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Could shorten by assigning p=process first to avoid repetition. Just plain #!env node works unless you've got a non-standard filesystem layout or funky $PATH stuff going on. Alternatively, drop the shebang line (so the default sh is used) and do node -e '<program>' because that's the same (6) extra number of characters and stays system-general. (If you want to join the dark side, rename your node binary to n.) Aaand drop the semicolon. \$\endgroup\$
    – Anko
    Sep 15, 2014 at 9:41
5
\$\begingroup\$

Perl (1)

0+1 for the -p parameter

If really the shebang counts, invoke it like this: perl -p nul on M$ or perl -p /dev/null on *nix so no shebang is involved :P

D:\>copy con cat.pl
#!perl -p
^Z
        1 file(s) copied.

D:\>type cat.pl
#!perl -p

D:\>type cat.pl | cat.pl
#!perl -p

D:\>
\$\endgroup\$
5
\$\begingroup\$

Bash, 3

If you need a shebang, #!/bin/sh or #!/bin/bash is probably fine.

Had to be done. Hopelessly uncreative.

cat

Slightly more interesting:

tee

Normally, tee FILENAME sends its input both to the file and to standard output. Without an argument, it seems to behave like cat.

Bash, 2

...if you don't mind the status message at the end and the fact that the output only comes after EOF on standard input!

dd

Removing the status message costs 4 chars for a total of 6 chars:

dd 2>a

The message is sent to the file a instead of standard output.

If you dispose of the message entirely, the total length is 14 7:

dd 2>&-

Bash/SHELF, 1

For the shebang, try

#!/bin/sh
. shelf.sh

where shelf.sh is the location of your SHELF file.

SHELF is my PYG-like golfing library for Bash.

D

D just aliases to cat. Also uncreative.

And the alias for tee is...

5
\$\endgroup\$
1
  • 2
    \$\begingroup\$ 2>&- is shorter than 2>/dev/null. \$\endgroup\$ Jun 26, 2014 at 11:35
5
\$\begingroup\$

Linux/Unix tools, 16 bytes

#!/bin/sh
grep $

Other tools that work when called by bash/sh are

tr . .

and (15 bytes)

sed n

EDIT: Changed title from "bash/sh" to "Linux/Unix tools" because although the tools can be called by bash or sh they aren't actually part of bash or sh.

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Copies the indentation? \$\endgroup\$
    – seequ
    Jun 15, 2014 at 12:54
  • \$\begingroup\$ @TheRare yes. It copies "all stdin to the stdout," as required. I guess that the 2-space indentation requirement refers to indentation of the code. \$\endgroup\$ Jun 15, 2014 at 12:59
  • 1
    \$\begingroup\$ Yes, yes it does. \$\endgroup\$
    – seequ
    Jun 15, 2014 at 13:01
  • \$\begingroup\$ shebangs don't count towards your score (and why are they #!/bin/sh? that isn't bash) \$\endgroup\$
    – user16402
    Jun 18, 2014 at 16:35
  • \$\begingroup\$ @professorish /bin/sh is Bash on my platform (Ubuntu 14.04) Perhaps I should have said Ubuntu and RedHat Fedora in my answer instead of "many systems" (will edit accordingly). In the example for ruby shown in the question, the shebang is counted among the 44 bytes. \$\endgroup\$ Jun 18, 2014 at 16:47
4
\$\begingroup\$

CJam - 1

q

No extra newline :)

\$\endgroup\$
3
\$\begingroup\$

AWK - ???

The complete program in awk has only 1 char:

1

Unluckily the shebang stuff lets kinda explode it's length :(

#!/usr/bin/awk -f
1

May I copy awk into the filesystem root? >;-)

As oneliner it is shorter:

$ awk 1 </etc/hostname 
darkstar

I'm not sure what counts and what not...

\$\endgroup\$
4
  • 5
    \$\begingroup\$ In my experience, code in codegolf doesn't use shebangs, it is intended to be directly executed by the interpreter (awk in this case). \$\endgroup\$ Jun 15, 2014 at 13:42
  • \$\begingroup\$ Thinking about stdout = g(f(stdin))... <input tac|tac >output fails if the last input line has no linefeed. I like <input rev|rev >output. So far for f = g. What comes into the game for f != g? tr and it's inverse? sed and backwards? Smells not really promising... \$\endgroup\$
    – user19214
    Jun 17, 2014 at 14:59
  • \$\begingroup\$ A flash of enlightenment hit me: tee ftw!!! :) \$\endgroup\$
    – user19214
    Jun 18, 2014 at 14:35
  • \$\begingroup\$ At least in OpenBSD, printf 'full\0string' | awk 1 outputs 'full\n', so it is not perfect. I wonder if gawk or mawk does better? \$\endgroup\$
    – kernigh
    Jun 20, 2014 at 21:01
3
\$\begingroup\$

16 bit .com binary for MSDOS - 31 Bytes (112 Byte NASM Source)

00 00 BA 00 00 B9 01 00 B4 3F BB 00 00 CD 21 83 F8 00 74 09 B4 40 BB 01 00 CD 21 EB EB CD 20

The nasm source code:

c:resw 1
mov dx,c
mov cx,1
r:
mov ah,63
mov bx,0
int 33
cmp ax,0
je e
mov ah,64
mov bx,1
int 33
jmp r
e:
int 32

Build with "nasm -f bin -o cat.com cat-msdos.s".

I already provided a solution for x86_64 Linux, but was unable to get it under 100 bytes. This is over 100 bytes of assembly, but the actually binary is only 31 bytes! This must be the simplest solution here.

\$\endgroup\$
3
\$\begingroup\$

Ruby, 2 bytes (or 1?)

#!/usr/bin/env ruby -p

The question states that the shabang needs to be included. The 2 bytes counted is the -p part of the shebang. The otherwise empty script makes Ruby behave exactly likes cat when run with the p switch: Run it without arguments and it will take input from stdin, or with arguments and it print the contents of those files.

edit:

Ruby, 8 bytes

@core1024 had already posted a solution in Perl similar to the one above, so here is another attempt. Note that the following are not scripts, they are Ruby programs ;)

puts *$<

Ruby, 16 bytes

I think this one is cute

print while gets
\$\endgroup\$
2
\$\begingroup\$

Python 2.x - 56 or 61 bytes

Input limited to 10^9 bytes.

#!/usr/bin/python
from os import*
write(1,read(0,10**9))

Or for infinite input (61 bytes):

#!/usr/bin/python
from sys import*
stdout.write(stdin.read())

Not much to say, is there?

\$\endgroup\$
11
  • 1
    \$\begingroup\$ This isn't cat because it adds a linefeed or whatever your system uses (cr+lf?) to the output. \$\endgroup\$
    – user19214
    Jun 15, 2014 at 13:29
  • \$\begingroup\$ @yeti You're right. I use Windows atm, so couldn't remember that. Fixing... \$\endgroup\$
    – seequ
    Jun 15, 2014 at 13:39
  • \$\begingroup\$ @yeti Better now? \$\endgroup\$
    – seequ
    Jun 15, 2014 at 13:56
  • \$\begingroup\$ You can use 1e9 instead of 10**9 to save 2 characters. Also, the shebang doesn't count towards character count. \$\endgroup\$ Jun 15, 2014 at 14:02
  • 1
    \$\begingroup\$ @nyuszika7h That prints an extra space. \$\endgroup\$
    – seequ
    Jun 15, 2014 at 15:05
2
\$\begingroup\$

Batch (8)

type CON

Type writes file content to the console and CON is treated as a file containing all console input.

\$\endgroup\$
1
  • \$\begingroup\$ I like how this has a one-to-one correspondence with Bash: type to cat, con to /dev/stdin \$\endgroup\$
    – clapp
    Dec 4, 2015 at 16:33
2
\$\begingroup\$

Common Lisp

ECL, 106

#!/usr/local/bin/ecl -shell
(ignore-errors(loop(write-byte(read-byte *standard-input*)*standard-output*)))

SBCL, 109

#!/usr/local/bin/sbcl --script
(ignore-errors(loop(write-byte(read-byte *standard-input*)*standard-output*)))

CLISP, 188 180

#!/usr/local/bin/clisp
(let((i(make-stream 0 :element-type'(mod 256)))(o(make-stream 1
:direction :output :element-type'(mod
256))))(ignore-errors(loop(write-byte(read-byte i)o))))

These are the shortest programs that I can make, yet none are under 100 bytes.

The main problem is that *standard-input* and *standard-output* are character streams, not byte streams. A simple (loop(write-char(read-char)) would copy the characters but would fail to preserve bytes that did not form valid characters. Now my Common Lisp implementations want to use UTF-8 (perhaps because my locale is UTF-8), but I want to copy binary files that my not be valid UTF-8. Therefore I must copy bytes, not characters.

In ECL and SBCL, standard input and output are bivalent for both bytes and characters. I may use read-byte and write-byte, but those functions lack default streams, so I must pass *standard-input* and *standard-output* as arguments.

CLISP insists that *standard-input* and *standard-output* transport only characters. The way around this is to call ext:make-stream on file descriptor 0 (standard input) and file descriptor 1 (standard output) to make binary streams.

All three programs loop byte by byte. This is a slow way to copy bytes. A faster way would use a vector of 16384 bytes with read-sequence and write-sequence, but the program would be longer.

\$\endgroup\$
2
\$\begingroup\$

zsh, 15 bytes

#!/bin/zsh
1<&1

Note that there is no newline at the end of the file.

\$\endgroup\$
2
\$\begingroup\$

Some Perl:

#!/usr/bin/perl
print<>;

25 bytes with shebang. This can also be much smaller with die(), and by bending the rules ever so slightly:

die<>

Executing the 4th test could only be done like this:

cat bla|perl ./perlcat 2>&1|diff bla -

<> is an abbreviation for <STDIN>. The 25 byte print example is pretty self explanatory. die() is normally used for exiting non-zero and outputting an error message, hence using the 2>&1 to bend the rules around the 4th test.

It also appears that the semicolon is not required for the last statement in Perl, so the first example could be brought down to 24 bytes.

\$\endgroup\$
2
\$\begingroup\$

><>, 7 bytes

I know a ><> solution already exists, but I figured it would be welcome.

i:0(?;o

Click here to try it

\$\endgroup\$
2
\$\begingroup\$

Java 68 104

My first approach at this:

class a{public static void main(String[]a){System.out.print(a[0]);}}

EDIT: Yeah, I misunderstood the concept, here is another attempt, I couldn't get it done in less than 100 chars so I'd appreciate any suggestion:

class a{public static void main(String[]a)throws Exception{for(;;)System.out.write(System.in.read());}}
\$\endgroup\$
3
  • 1
    \$\begingroup\$ That's not how cat works. cat displays the contents of the file(s) given as command line arguments, or takes input from stdin when there are no arguments. \$\endgroup\$
    – daniero
    Jun 24, 2014 at 23:16
  • 1
    \$\begingroup\$ @daniero Yeah I wasn't right, it works now, although much longer. \$\endgroup\$
    – BrunoJ
    Jun 25, 2014 at 18:33
  • \$\begingroup\$ This breaks the rule about looping forever, how about: class a{public static void main(String[]a)throws Exception{int r;while(0<(r=System.in.read()))System.out.write(r);}} \$\endgroup\$ Sep 15, 2014 at 11:29
2
\$\begingroup\$

TI-BASIC, 12

While 1:Input Str1:Disp Str1:End
\$\endgroup\$
3
  • \$\begingroup\$ Use "Str1" instead of "A". \$\endgroup\$ Oct 28, 2015 at 5:01
  • \$\begingroup\$ @CᴏɴᴏʀO'Bʀɪᴇɴ Thanks for the tip, I was really bad at TI-Basic a year ago. Only problem is you can't use the STO-> arrow but you couldn't before either. It seems so silly that I used A instead of a string var :P again, thanks for the tip! \$\endgroup\$
    – Timtech
    Oct 29, 2015 at 0:46
  • \$\begingroup\$ @ThomasKwa Good idea. \$\endgroup\$
    – Timtech
    Oct 29, 2015 at 21:39
2
\$\begingroup\$

Perl6, 14 bytes:

.say for lines

And, if it doesn't need to be deterministically printing it in the correct order (hehe), you can use the auto-threading "map-apply"

lines>>.say
\$\endgroup\$
1
\$\begingroup\$

GML, 37

while(1)show_message(keyboard_string)
\$\endgroup\$
1
\$\begingroup\$

Rust - 74

Really generic...

use std::io;fn main(){for l in io::stdin().lines(){io::print(l.unwrap())}}

No Comment - 12

'=|@^:'&|:'&

Unimplemented, so, yeah.

\$\endgroup\$
1
\$\begingroup\$

Dart - 48

import"dart:io";main(){stdout.addStream(stdin);}
\$\endgroup\$
1
\$\begingroup\$

Groovy - 45 bytes

#!/usr/bin/env groovy
System.out << System.in

And test:

$ cat FirstJsonObj.groovy | ./Cats.groovy | diff FirstJsonObj.groovy  -
$ 
\$\endgroup\$
1
\$\begingroup\$

Tcl 57

#!/usr/bin/env expect
while {[gets stdin d]>=0} {puts $d}
\$\endgroup\$
1
\$\begingroup\$

Swift, 32

while let l=readLine(){print(l)}

Prints every line until EOF is reached

If you're really picky that this doesn't work with an empty line at the end or whatever you can use this:

while let l=readLine(stripNewline:false){print(l,terminator:"")}
\$\endgroup\$
1
\$\begingroup\$

MATLAB, 18 bytes

fprintf(input(''))

Cannot use disp as it appends a newline to the output.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.