J'ai plusieurs fichiers avec le même en-tête et différents vecteurs en dessous. J'ai besoin de les concaténer tous mais je veux que seul l'en-tête du premier fichier soit concaténé et je ne veux pas que les autres en-têtes soient concaténés car ils sont tous les mêmes.
par exemple: file1.txt
<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B
C
file2.txt
<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
D
E
F
J'ai besoin que la sortie soit
<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B
C
D
E
F
Je pourrais écrire un script en R mais j'en ai besoin en shell?
Si vous savez comment le faire en R, alors faites-le certainement en R. Avec les outils Unix classiques, cela se fait le plus naturellement dans awk.
awk '
FNR==1 && NR!=1 { while (/^<header>/) getline; }
1 {print}
' file*.txt >all.txt
La première ligne du script awk correspond à la première ligne d'un fichier (FNR==1
) Sauf s'il s'agit également de la première ligne de tous les fichiers (NR==1
). Lorsque ces conditions sont remplies, l'expression while (/^<header>/) getline;
est exécutée, ce qui oblige awk à continuer de lire une autre ligne (en sautant la ligne actuelle) tant que la ligne actuelle correspond à l'expression régulière ^<header>
. La deuxième ligne du script awk imprime tout sauf les lignes qui ont été précédemment ignorées.
Une autre solution, similaire à "cat+grep
"d'en haut, en utilisant tail
et head
:
Écrivez l'en-tête du premier fichier dans la sortie:
head -2 file1.txt > all.txt
- head -2
obtient 2 premières lignes du fichier.
Ajoutez le contenu de tous les fichiers:
tail -n +3 -q file*.txt >> all.txt
- -n +3
fait tail
imprimer les lignes du 3ème à la fin, -q
lui dit de ne pas imprimer l'en-tête avec le nom du fichier (lire man
), >>
ajoute au fichier, ne le remplace pas par >
.
Et bien sûr, vous pouvez mettre les deux commandes sur une seule ligne:
head -2 file1.txt > all.txt; tail -n +3 -q file*.txt >> all.txt
ou au lieu de ;
mettre &&
entre eux pour vérifier la réussite.
Essayez de faire ceci:
$ cat file1.txt; grep -v "^<header" file2.txt
<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B
C
D
E
F
-v
flag signifie inverser la correspondance de grep^
in REGEX , signifie début de la chaîne :
array=( files*.txt )
{ cat ${array[@]:0:1}; grep -v "^<header" ${array[@]:1}; } > new_file.txt
C'est une technique de découpage bash array.
Plus court (pas nécessairement plus rapide) avec sed
:
sed -e '3,${/^<header>/d' -e '}' file*.txt > all.txt
Cela supprimera toutes les lignes commençant par <header>...
à partir de la ligne 3, donc le premier en-tête est conservé et les autres en-têtes sont supprimés. S'il y a un nombre différent de lignes dans l'en-tête, ajustez la commande en conséquence (par exemple, pour l'en-tête à 6 lignes, utilisez 7
au lieu de 3
).
Si le nombre de lignes dans l'en-tête est inconnu, vous pouvez essayer comme ceci:
sed '1{
: again
n
/^<header>/b again
}
/^<header>/d
' file*.txt > all.txt
La commande tail
(sur GNU, au moins) a une option pour ignorer un nombre donné de lignes initiales. Pour imprimer à partir de la deuxième ligne, c'est-à-dire ignorer un en-tête d'une ligne, procédez comme suit: tail -n+2 myfile
Donc, pour garder l'en-tête à deux lignes du premier fichier mais pas du second, dans Bash:
cat file1.txt <(tail -n+3 file2.txt) > combined.txt
Ou, pour de nombreux fichiers:
head -n1 file1.txt > combined.txt
for fname in *.txt
do
tail -n+3 $fname >> combined.txt
done
Si une certaine chaîne est connue pour être présente dans toutes les lignes d'en-tête mais jamais dans le reste des fichiers d'entrée, grep -v
est une approche plus simple, comme l'a montré spoutnik.
array = (* .txt); head -1 $ {array [0]}> all.txt; tail -n +2 -q $ {array [@]: 0} >> all.txt
En supposant que vous utilisez un dossier avec des fichiers .txt avec le même en-tête qui doivent être combinés/concaténés, ce code combinerait tous les fichiers txt en all.txt avec un seul en-tête. la première ligne (lignes séparées par des points-virgules) rassemble tous les fichiers texte à concaténer, les secondes lignes sortent l'en-tête du premier fichier txt dans all.txt, et la dernière ligne concatène tous les fichiers texte rassemblés sans l'en-tête (en commençant la concaténation à partir de la ligne 2) et l'ajoute à all.txt.