6
votes

Script Shell - Lisez deux lignes de fichier et lisez une ligne d'un autre fichier

dire, j'ai deux fichiers.

File1 Contient: P>

line1
line2
anotherline1
line3
line4
anotherline2
line5
line6
anotherline3
line7
line8
anotherline1
line9
line10
anotherline2


5 commentaires

BTW - Comment voulez-vous que cela se comporte si le nombre de lignes dans les deux fichiers d'entrée ne correspond pas (une ligne dans File2 pour toutes les deux lignes de fichier1)?


La "tandis que la boucle" devrait être jusqu'à atteindre la fin du fichier1. Peu importe la durée de file2, réellement, dans mon scénario personnel, File2 sera toujours plus courte que FILE1. La sortie doit être: File1Line1, File1Line2, File2line1, File1Line3, File1Line4, File2line2 .... etc.


Vous pouvez envisager d'éditer cela dans votre question; Cela change de manière significative ce qui constitue une réponse correcte.


Après avoir frappé la fin de fichier2, il y en avoir des blancs pour les lignes qui en viendraient autrement, ou devraient-elles simplement être laissées de côté?


Ajouté à la question. Merci mon mauvais. ^ _ ^ U


4 Réponses :


2
votes

Je ne connais pas de manière pratique de faire quelque chose qui spécifique dans le script pur shell. Vous ferez probablement mieux d'écrire un python / Perl / etc. scénario. Quelque chose comme ce script awk fonctionnerait, mais c'est un peu désordonné: xxx

le impression; getline; Imprimer imprimera la ligne suivante à partir de File1, obtenez la ligne après cela, puis imprimez-la. Le si (! Getline <"fichier2") essaie de lire la ligne suivante à partir du fichier2, et si elle échoue, la ferme, le répète implicitement et lit la première ligne de File2. La finale impression imprimera cette ligne de File2 (prochain ou premier).


6 commentaires

Une explication de votre façon de fonctionner serait très éducative! :-)


Donc, si j'ajoute> File3 à la fin, la sortie serait ce que je veux? Je vais essayer ça maintenant ...


(Pour être clair, la seule chose que je m'oppose ici est la prétention que cela ne peut pas être fait dans Pure Shell - voir ma réponse pour un contre-exemple - c'est autrement parfaitement parfait).


@ghoti a ajouté une explication.


@CharlesDuffy En effet, j'ai évoqué votre réponse depuis que j'aime l'utilisation de descripteurs de fichiers (et ajusté ma réponse pour indiquer mon ignorance).


C'est beaucoup plus facile à lire maintenant. J'aime la logique simple de cette réponse. Upvoted. :)



1
votes

Facilement effectué dans une coquille natale - aucun outil externe tel que awk nécessaire. Ouvrez deux descripteurs de fichier, liés à différents fichiers et itérer sur les deux. xxx

Dans ce cas, 3 est le numéro de descripteur de fichier sur lequel nous avons ouvert File1 et 4 est le numéro de descripteur de fichier sur lequel nous avons ouvert File2 . 1> FILE3 ou simplement > FILE3 , REROUTES Sortie sur le descripteur de fichier 1 (AKA stdout) dans le fichier de sortie. < P> Vous pouvez choisir d'autres nombres si vous avez aimé, mais seulement la plage comprise entre 3 et 9 est garantie pour être utilisée sur toutes les coquilles POSIX. (0-2 sont stdin, stdout et stardr; au-dessus de 10 peuvent être utilisés par la coque pour son propre usage, bien que cela soit rarement le cas dans des coquilles plus récentes et plus modernes).


4 commentaires

Ceci (premier exemple) est à peu près ce que je voulais. Bien que le moment se termine également s'il atteigne la fin du fichier2, et je veux que cela continue à aller jusqu'à la lecture de toutes les lignes de fichier1.


Continuez et faites quoi? Ajouter des lignes vides lorsque le contenu de File2 serait autrement? Ajoutez simplement plus de lignes de File1?


Premier exemple modifié pour ignorer EOF sur File2.


@ user3246010, ahh. J'ai dû relire la question un peu pour rassembler que vous vouliez démarrer File2 du haut. Spécifier qu'en anglais plutôt que seul, par exemple n'aurait été apprécié.



2
votes

Cet awk devrait fonctionner: xxx pré>

edit: strong> Même plus court awk code> (merci à @geirha ): P>

awk 'FNR==NR{a[n++]=$0;next}1;!(FNR%2){print a[i++%n]}' file2 file1


2 commentaires

Voici une version de golf, pour le plaisir awk 'fnr == nr {a [n ++] = 0 $; suivant} 1 1;! (FNR% 2) {Imprimer a [I ++% N]}' File2 File1


Wow c'est encore mieux (ajouté en réponse).



3
votes

Si je vous interprète correctement votre question, vous voulez

  1. étape par fichier1 code> début à la fin et li>
  2. Insérez la ligne "Suivant" à partir de File2 code> après toutes les deux lignes, tournez vers le haut de File2 code> chaque fois que vous manquez de contenu. LI> ol>

    Si c'est le but, vous pouvez le faire avec Awk de différentes manières, mais l'extrait de coque suivant ferait probablement. P>

    #!/usr/bin/env bash
    
    mapfile -t file2 < file2
    
    max=${#file2[@]}
    
    while read line; do
      ((count++))
      echo "$line"
      if [[ $((count%2)) == 0 ]]; then
        if [[ next -ge max ]]; then
          next=0
        fi
        echo "${file2[next++]}"
      fi
    done < file1
    


5 commentaires

Où obtenez-vous le comportement "rotatif"? Je ne vois aucune spécification (autre que le programme ne doit pas quitter ce point).


Peut-être envisager de spécifier explicitement le besoin de Bash 4.x ici, d'utilisation de MapFile .


(BTW, il y a sont façons faciles de rouvrir le fichier2 sur la frappe de la fin; on pourrait lire <& 3 || {exécu 3 , par exemple ).


CETTE !!! Cela a travaillé comme je le voulais. Je m'excuse vraiment si j'ai fait ma question trop compliquée. Mais cela résolvait certainement. JE VOUS REMERCIE!!


@CHARLESDUFFY, grand point sur Bash 4 - J'ai modifié cette réponse. En ce qui concerne "des façons faciles", je dirais que plusieurs poignées de fichier sont une fonctionnalité de script plus avancée que des tableaux et pourraient donc ne pas être "plus faciles" pour une personne qui ne connaissait pas déjà leur utilisation. Merci pour vos suggestions.