The puppy utility takes a filename as input, and does exactly what you would expect a puppy to do: it shreds it!


How to shred

  1. Rip out the pages with your teeth Split the input file on newlines.
  2. Tear up each page with your paws For each line (not including the linefeed), pick a random integer n such that 2 <= n <= # of characters in the line. Split the line into n non-empty non-overlapping substrings of random length.
  3. Scatter the shreds all over the floor Output each substring of each line to a unique random filename ([a-zA-Z0-9] only, any consistent extension including none, length 1 <= n <= 12) in the current directory. Overwriting pre-existing files within the current directory (including the input file, if it is in the current directory) is acceptable, as long as it does not interfere with your submission running.


  • There will never be an input where it is possible to use up all of the possible filenames.
  • Files will consist of only printable ASCII (ordinals 32-127) and linefeeds, and will use UNIX/Linux-style line endings (LF, not the Windows-style CRLF).
  • A single trailing newline in output files is acceptable as long as every output file has a trailing newline, but is not required. You may choose whether or not the input file contains a trailing newline.
  • Each line in the input will contain at least 2 characters.
  • The random values chosen must be chosen from a uniform random distribution on the given set of possible values.

If your language is unable to perform file I/O, you may instead take the input file's contents as input, and output pairs of strings representing the output filename and the text for that file. However, your submission will not be eligible for winning.


Reference implementation:

#!/usr/bin/env python3

import random
import string
import sys

fname = sys.argv[1]
with open(fname) as f:
  txt = f.read().rstrip().split('\n')
for line in txt:
  n = random.randint(2, len(line))-1
  idxs = [0]+random.sample(range(1, len(line)), n)+[len(line)]
  splits = []
  for i in range(0, len(idxs)-1):
  ofnames = []
  for s in splits:
    flen = random.randint(1, 10)
    ofname = ''
    while ofname == '' or ofname in ofnames:
      ofname = ''
      for i in range(flen):
        ofname += random.choice(string.ascii_letters+string.digits)
    with open(ofname, 'w') as f:

Example run:

$ cat bestsong.txt
Never gonna give you up
Never gonna let you down
Never gonna run around
And desert you!

$ puppy bestsong.txt

$ ls

$ cat 8675309
esert you!

$ cat a
Never gonna let you down

$ cat cSdhg
ive y

$ cat Dq762
And d

$ cat jq7t
Never gonna g

$ cat ret865
run arou

$ cat rick4life
Never gonna 

$ cat weu767g

$ cat xyzzy
ou up

2 Answers 2


PowerShell v2+, 215 211 bytes

nal d Get-Random;gc $args[0]|%{$b=d(0..($l=($t=$_).length)) -C(d(2..$l));$b=$b+0+$l|select -u|sort;0..($b.count-2)|%{-join($t[$b[$_]..($b[$_+1]-1)])}}|%{$_>(-join[char[]](d(48..57+65..90+97..122) -c(d(1..12))))}

Requires v2 or newer since v1 didn't have Get-Random available.
Edit -- saved 4 bytes by using char-array casting instead of individually casting each letter

Somewhat Ungolfed

Get-Content $args[0]|ForEach-Object{
  $b=Get-Random(0..$l) -Count(Get-Random(2..$l))
  $b=$b+0+$l|Select-Object -unique|Sort-Object
  $_>(-join[char[]](Get-Random(48..57+65..90+97..122) -count(Get-Random(1..12))))


Starts with setting d as a New-Alias for Get-Random, so we don't have to type out Get-Random each time we're using it (a lot). We then Get-Content of our input $args and pipe those through a loop with |%{...}. Note that Get-Content will by default split on newlines (either CRLF or just LF), so we don't need to do anything additional there.

Each iteration of the loop, we start with formulating the slices this line is going to be Ginsu'd into. Set $t equal to the line we're working with, and $l equal to its length, then construct a collection from (0..$l). This represents all possible character indices in our current line. We then Get-Random from between (2..$l) to determine how many to select, and then get a random number of indices equal to that -count. Store those indices in $b.

We then also add on 0 and $l to $b, so we have the beginning and end of our line guaranteed to be in the collection of indices. Pipe that through to Select-Object with the -unique flag, then pipe to Sort-Object, so our indices are now guaranteed to start with the first character and end with the last character, and some random number in between.

Next, we're looping over all the indices in $b with 0..($b.count-2)|%{...}. Each of those loop iterations, we're slicing $t (our current line of text) and then -joining them together into a string (rather than a char-array). Those get bundled up and left on the pipeline, and we close the outer loop.

So now we have an in-order collection of random slices of each of the lines of text. (Meaning, at this point, if we simply -joined them back together, we'll get the original text minus newlines.) We then pipe that collection through another loop |%{...} and each iteration we're outputting that slice to a file with $_>.... The file is created by taking from 1 to 12 random integers that correspond with ASCII codes for [0-9A-Za-z]. No file will have an extension, and the > command will output a trailing newline by default on every file.


Example run


APL (Dyalog Unicode), 85 80 67 62 bytes


Try it online!

This was a fun one.

Full program which takes a string as input, and outputs files to wherever the ]cd command points to in the Dyalog workspace.

Done with some advice from dzaima.

-13 bytes from Bubbler, by removing ⎕UCS 10. -5 more bytes from Bubbler after some more smaller golfs and change to the sorting idiom.


Input file is a list of numbers from 1-99 from my "Size Up a Number" challenge.

enter image description here


⊃⎕NGET⍞1 read file from location as APL array, take first element, split on newlines. (mode 1)

(last two elements are file attributes)

{⍵⊆⍨(⊂∘⍋⌷⊢)?(/⍨≢⍵)}¨ for each line, execute the following:

(/⍨≢⍵) create a list of the length repeated length times

? generate random numbers within those ranges

(⊂∘⍋⌷⊢) sort in ascending order

⍵⊆⍨ partition the line according to the sorted array

⊃,/ join into a single vector and remove nesting

{⍵⎕NPUT(⎕A,(¯1∘⎕C⎕A),⎕D)[?(?12)/62]1} for each partition, do the following:

(⎕A, ) create a list with the uppercase alphabet,

( (¯1∘⎕C⎕A) ) the lowercase alphabet,

( ,⎕D) and numbers from 0-9.

[ (?12) ] generate a random number in range 1-12

[ /62] replicate 62 that many times

[? ] create that many random numbers in range 1-62, and index into the list.

⍵⎕NPUT 1 write the partition into the random filename, creating it if necessary.

  • 1
    \$\begingroup\$ ⎕NGET has a mode to auto-split the contents by newlines, so it should work if you replace (⎕UCS 10)(≠⊆⊢)⊃⎕NGET⍞ with simply ⊃⎕NGET⍞1. \$\endgroup\$
    – Bubbler
    Oct 5, 2020 at 2:26
  • \$\begingroup\$ Also (/⍨≢⍵) can be ⍴⍨≢⍵ (saving parentheses), (⊂∘⍋⌷⊢) can be (⍋⊃¨⊂) (a variant of sorting idiom that works only with vectors), (?12)/62 can be 62/⍨?12, and you can remove from ⎕A,⎕D,¯1∘⎕C⎕A. \$\endgroup\$
    – Bubbler
    Oct 5, 2020 at 2:31
  • \$\begingroup\$ thanks a lot. @Bubbler \$\endgroup\$
    – Razetime
    Oct 5, 2020 at 5:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.