dd: plusieurs fichiers d'entrée

14

J'ai besoin de concaténer des morceaux de deux fichiers:

si j'avais besoin de concaténer des fichiers entiers, je pourrais simplement faire

cat file1 file2 > output

Mais je dois ignorer le premier 1 Mo du premier fichier et je ne veux que 10 Mo du deuxième fichier. Cela ressemble à un travail pour dd.

dd if=file1 bs=1M count=99 skip=1 of=temp1
dd if=file2 bs=1M count=10 of=temp2
cat temp1 temp2 > final_output

Est-il possible de le faire en une seule étape? c'est-à-dire sans avoir besoin de sauvegarder les résultats intermédiaires? Puis-je utiliser plusieurs fichiers d'entrée dans dd?

Martin Vegter
la source

Réponses:

21

dd peut également écrire sur stdout.

( dd if=file1 bs=1M count=99 skip=1
  dd if=file2 bs=1M count=10  ) > final_output
meuh
la source
C'est probablement le meilleur moyen. Le fichier de sortie n'est pas fermé / rouvert (comme c'est le cas avec oflag=append conv=notrunc), donc les systèmes de fichiers qui font une allocation retardée (comme XFS) sont moins susceptibles de décider que le fichier est terminé en cours d'écriture alors qu'il reste encore du chemin à parcourir.
Peter Cordes
@PeterCordes, c'est un bon point, mais tant ddqu'on ne le lui demande pas sync, l'allocation retardée ne devrait pas démarrer immédiatement de toute façon (sauf si la mémoire est insuffisante, auquel cas aucune des méthodes ne retardera l'allocation).
Stephen Kitt
@StephenKitt: Vous avez probablement raison. Je pensais à la préallocation spéculative de XFS , où il doit détecter spécialement le modèle d'accès de fermeture / réouverture (parfois vu pour les fichiers journaux).
Peter Cordes
3
Dans des shells comme bashet mkshqui n'optimisent pas le fork de la dernière commande d'un sous-shell, vous pouvez le rendre légèrement plus efficace en remplaçant le sous-shell par un groupe de commandes. Pour les autres shells, cela ne devrait pas avoir d'importance, et l'approche des sous-shells pourrait même être légèrement plus efficace car le shell n'a pas besoin de sauvegarder et de restaurer stdout.
Stéphane Chazelas
10

Je ne pense pas que vous puissiez facilement lire plusieurs fichiers en une seule ddinvocation, mais vous pouvez ajouter pour créer le fichier de sortie en plusieurs étapes:

dd if=file1 bs=1M count=99 skip=1 of=final_output
dd if=file2 bs=1M count=10 of=final_output oflag=append conv=notrunc

Vous devez spécifier les deux conv=notruncet oflag=append. Le premier évite de tronquer la sortie, le second commence à écrire à partir de la fin du fichier existant.

Stephen Kitt
la source
8

Gardez à l' esprit que ddest une interface première au read(), write()et lseek()appel système. Vous ne pouvez l'utiliser que de manière fiable pour extraire des morceaux de données de fichiers normaux, bloquer des périphériques et certains périphériques de caractères (comme /dev/urandom), c'est-à-dire des fichiers pour lesquels il read(buf, size)est garanti de revenir sizetant que la fin du fichier n'est pas atteinte.

Pour les tuyaux, les sockets et la plupart des périphériques de caractères (comme ttys), vous n'avez aucune garantie à moins que vous n'utilisiez la read()taille 1 ou que vous utilisiez l' ddextension GNU iflag=fullblock.

Alors soit:

{
  gdd < file1 bs=1M iflag=fullblock count=99 skip=1
  gdd < file2 bs=1M iflag=fullblock count=10
} > final_output

Ou:

M=1048576
{
  dd < file1 bs=1 count="$((99*M))" skip="$M"
  dd < file2 bs=1 count="$((10*M))"
} > final_output

Ou avec des coques avec support intégré pour un opérateur de recherche comme ksh93:

M=1048576
{
  command /opt/ast/bin/head -c "$((99*M))" < file1 <#((M))
  command /opt/ast/bin/head -c "$((10*M))" < file2
}

Ou zsh(en supposant que votre headsupporte l' -coption ici):

zmodload zsh/system &&
{
  sysseek 1048576 && head -c 99M &&
  head -c 10M < file2
} < file1 > final_output
Stéphane Chazelas
la source
Avez-vous vraiment besoin des devis? Le résultat ne sera-t-il pas toujours un entier?
Steven Penny
@StevenPenny, laisser l'expansion sans guillemets demande au shell de le diviser + de le globaliser, ce qui n'aurait aucun sens ici. La partie scindée se fait sur la valeur courante de $IFS. C'est indépendamment du contenu de la variable / expansion. Voir aussi Conséquences pour la sécurité d'oublier de citer une variable dans des shells bash / POSIX
Stéphane Chazelas
@ Stéphane Chazelas - dans le premier exemple, vous utilisez à la gddplace de dd. Est-ce une faute de frappe, ou est-ce intentionnel?
Martin Vegter
3

Avec un isme bash , et une "utilisation inutile de cat " fonctionnellement, mais plus proche de la syntaxe que l'OP utilise:

cat <(dd if=file1 bs=1M count=99 skip=1) \
    <(dd if=file2 bs=1M count=10) \
   > final_output

(Cela étant dit, la réponse de Stephen Kitt semble être la méthode la plus efficace possible.)

agc
la source
3
À proprement parler, <(...)est un kshisme qui a copié zshet bashcopié.
Stéphane Chazelas