Implement the dog bash utility

10

1

dog is a command-line utility that takes in an arbitrary number of arguments, the first of which is the text to be written and the others are arbitrarily many files.

The dog utility will split the text in equal portions over these files. If there is a remainder n, the first n files get an additional byte

dog is the opposite of cat, as such, forall x, the following should hold.

$> dog x a.txt b.txt ...
$> cat a.txt b.txt ...
x$>

Where ... indicates arbitrarily many files.

An example (12 bytes, 3 files, can be split evenly):

$> ./dog.py "Dogs vs Cats" a.txt b.txt c.txt
$> cat a.txt
Dogs$> cat b.txt
 vs $> cat c.txt
Cats$> cat a.txt b.txt c.txt
Dogs vs Cats$> 

An example with remainder (13 bytes, 5 files, remainder 3):

9$>./dog.py "0123456789abc" a.txt b.txt c.txt d.txt e.txt
$> cat a.txt
012$> cat b.txt
345$> cat c.txt
678$> cat d.txt
9a$> cat e.txt
bc$> cat a.txt b.txt c.txt d.txt e.txt
0123456789abc$>

Caridorc

Posted 2015-10-05T12:32:19.060

Reputation: 2 254

It's implied, but just to double check: 1) Do the arguments have to come in via command line? 2) Do we always have to output to files? – Sp3000 – 2015-10-05T12:35:35.013

@Sp3000 yes, to 1 and 2 – Caridorc – 2015-10-05T12:47:23.533

It would be more "unixy" for the input string to come from STDIN. But that's your call... – Digital Trauma – 2015-10-05T18:01:09.597

1@DigitalTrauma there's already an answer, I would feel bad for invalidating it by a rule change – Caridorc – 2015-10-05T18:06:29.317

2I've been learning about some oddly-named UNIX utilities from this site lately (tac, dog, ...). – kirbyfan64sos – 2015-10-06T14:08:37.143

@kirbyfan64sos They are non-existent, they are just word-puns over the cat util – Caridorc – 2015-10-06T14:13:36.407

Yeah, I know, but they're still weird, and I wouldn't be surprised if someone has actually named tools like that before. – kirbyfan64sos – 2015-10-06T14:14:23.303

1

@kirbyfan64sos and Caridorc: tac is real.

– DLosc – 2015-10-06T14:30:22.900

@DLosc funny, tac is an x-ray medical exam in Italian. I think it is just a coincidence though – Caridorc – 2015-10-06T14:33:09.603

@Caridorc Apparently the 'tac' scan is the language word order for a 'cat' scan in English (which is a special type of X-ray scan). The Xray (or at least what Americans would consider an X-ray - where you put up a static flat image) is raggi X. Oh, the joys that the 'other languages' sidebar on Wikipedia can bring. – None – 2015-10-07T21:19:30.597

I like the idea of *equal portions over these files* with at least 1 byte len as maximum difference! – F. Hauri – 2016-05-13T20:20:53.097

Answers

4

Pyth - 12 bytes

.wMC,cl.zz.z

Uses builtin split function and then uses splat-map on the write function. Doesn't work online.

Maltysen

Posted 2015-10-05T12:32:19.060

Reputation: 25 023

2

Python - 181 bytes

import sys
a=sys.argv
l=len
d=a[2:]
s=a[1]
n,r=divmod(l(s),l(d))
p=0
for i in range(l(d)):
    with open(d[i],'w') as f:
        o=n+int(i<=n)
        f.write(s[p:p+o])
        p+=o

Zac Crites

Posted 2015-10-05T12:32:19.060

Reputation: 201

1

PHP, 107 bytes

The golfed code:

for($i=1;++$i<$argc;fputs(fopen($argv[$i],w),substr($s=$argv[1],($i-2)*$l=ceil(strlen($s)/($argc-2)),$l)));

The detailed code:

$len = ceil(strlen($argv[1])/($argc - 2));
for ($i = 2; $i < $argc; $i ++) {
    $fh = fopen($argv[$i], 'w');
    fputs($fh, substr($argv[1], ($i - 2) * $len, $len));
    fclose($fh);          // omitted in the golfed version
}

axiac

Posted 2015-10-05T12:32:19.060

Reputation: 749

0

Pure bash: 97

s=$1;shift;for((l=${#s}/$#,m=${#s}-l*$#,i=1;i<=$#;p+=q,i++)){
printf "${s:p:q=i>m?l:l+1}">${!i};}

As a function: (p= is only required for second run)

dog() { p=
    s=$1;shift;for((l=${#s}/$#,m=${#s}-l*$#,i=1;i<=$#;p+=q,i++)){
    printf "${s:p:q=i>m?l:l+1}">${!i};}
}

Tests

$> rm *
$> dog "Dogs vs Cats" a.txt b.txt c.txt
$> ls -l
total 12
-rw-r--r-- 1 user user 4 May 13 22:09 a.txt
-rw-r--r-- 1 user user 4 May 13 22:09 b.txt
-rw-r--r-- 1 user user 4 May 13 22:09 c.txt
$> cat {a,b,c}.txt;echo
Dogs vs Cats
$> 

All files is 4 byte len and concatenated in right order, contain "Dogs vs Cats".

$> rm *
$> dog "$(printf "%s" {0..9} {a..c})" {a..e}.txt 
$> ls -l
total 20
-rw-r--r-- 1 user user 3 May 13 22:09 a.txt
-rw-r--r-- 1 user user 3 May 13 22:09 b.txt
-rw-r--r-- 1 user user 3 May 13 22:09 c.txt
-rw-r--r-- 1 user user 2 May 13 22:09 d.txt
-rw-r--r-- 1 user user 2 May 13 22:09 e.txt
$> cat *;echo
0123456789abc
$> 

Firsts files is 3 byte len and last only 2, concatenated by alphabetic order, contain "0123456789abc".

Explanation (ungolfing):

If you hit: declare -f dog, will answer:

$> declare -f dog
dog () 
{ 
    p=;
    s=$1;
    shift;
    for ((l=${#s}/$#,m=${#s}-l*$#,i=1; i<=$#; p+=q,i++))
    do
        printf "${s:p:q=i>m?l:l+1}" > ${!i};
    done
}

This could be written:

dog2 () 
{ 
    position=0;
    string=$1;
    shift;
    partLen=$((${#string}/$#));
    oneMore=$((${#string}-partLen*$#));
    for ((i=1; i<=$#; i++))
    do
        if ((i<=oneMore)); then
            partQuant=$((partLen+1));
        else
            partQuant=$partLen;
        fi;
        printf "${string:position:partQuant}" > ${!i};
        ((position+=partQuant));
    done
}

F. Hauri

Posted 2015-10-05T12:32:19.060

Reputation: 2 654

0

Ruby, 93 87 bytes

Full program using command line arguments.

If I could use s.slice! to mutate the string, I'd do that instead of needing to use s[c..-1], but Ruby doesn't let you mutate the strings from argv without duplicating them first

s,*t=$*
d,r=s.size.divmod t.size
t.map{|e|open(e,?w)<<s[0,c=(0>r-=1)?d:d+1];s=s[c..-1]}

Value Ink

Posted 2015-10-05T12:32:19.060

Reputation: 10 608