Implémenter l'utilitaire dog bash

10

dog est un utilitaire de ligne de commande qui accepte un nombre arbitraire d'arguments, le premier étant le texte à écrire et les autres étant arbitrairement de nombreux fichiers.

L' dogutilitaire divisera le texte en portions égales sur ces fichiers. S'il reste n, les premiers nfichiers reçoivent un octet supplémentaire

dogest le contraire de cat, en tant que tel, pour tous x, ce qui suit devrait tenir.

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

...indique arbitrairement de nombreux fichiers.

Un exemple (12 octets, 3 fichiers, peuvent être divisés uniformément):

$> ./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$> 

Un exemple avec le reste (13 octets, 5 fichiers, le reste 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
la source
C'est implicite, mais juste pour revérifier: 1) Les arguments doivent-ils entrer via la ligne de commande? 2) Devons-nous toujours produire des fichiers?
Sp3000
@ Sp3000 oui, à 1 et 2
Caridorc
1
@DigitalTrauma il y a déjà une réponse, je me sentirais mal de l'invalider par un changement de règle
Caridorc
2
J'ai récemment découvert certains utilitaires UNIX aux noms étranges (tac, dog, ...).
kirbyfan64sos
1
@ kirbyfan64sos et Caridorc: tacc'est réel .
DLosc

Réponses:

4

Pyth - 12 octets

.wMC,cl.zz.z

Utilise la fonction de division intégrée, puis utilise la carte de répartition sur la fonction d'écriture. Ne fonctionne pas en ligne.

Maltysen
la source
2

Python - 181 octets

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
la source
1

PHP, 107 octets

Le code golfé:

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

Le code détaillé:

$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
}
axiaque
la source
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};}

En fonction: ( p=n'est requis que pour la deuxième exécution)

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};}
}

Les 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
$> 

Tous les fichiers ont une longueur de 4 octets et sont concaténés dans le bon ordre, contiennent "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
$> 

Les premiers fichiers ont une longueur de 3 octets et les derniers seulement 2, concaténés par ordre alphabétique, contiennent "0123456789abc" .

Explication (dégoûtant):

Si vous frappez: declare -f dog, répondra:

$> 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
}

Cela pourrait s'écrire:

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
la source
0

Rubis, 93 87 octets

Programme complet utilisant des arguments de ligne de commande.

Si je pouvais utiliser s.slice!pour muter la chaîne, je le ferais au lieu d'avoir besoin de l'utiliser s[c..-1], mais Ruby ne vous laisse pas muter les chaînes d'argv sans les dupliquer au préalable

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]}
Encre de valeur
la source