J'ai deux fichiers texte: string.txt et lengths.txt
String.txt:
abcdefghijklmnopqrstuvwxyz
lengths.txt
5
4
10
7
Je veux obtenir le fichier
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
Je travaille avec environ 28 000 entrées et elles varient entre 200 et 56 000 caractères.
En ce moment, j'utilise:
start=1
end=0
i=0
while read read_l
do
let i=i+1
let end=end+read_l
echo -e ">Entry_$i" >>outfile.txt
echo "$(cut -c$start-$end String.txt)" >>outfile.txt
let start=start+read_l
echo $i
done <lengths.txt
Mais c'est très inefficace. De meilleures idées?
linux
shell-script
user3891532
la source
la source
str="$(cat string.txt)"; i=0; while read j; do echo "${file:$i:$j}"; i=$((i+j)); done <length.txt
.. semble assez rapide comme fait uniquement par shell ..{ while read l<&3; do head -c"$l"; echo; done 3<lengths.txt; } <String.txt
.Réponses:
Tu peux faire
Cela nécessite quelques explications:
L'idée principale est d'utiliser
{ head ; } <file
et est dérivée de la réponse @mikeserv sous-estimée . Cependant, dans ce cas, nous devons utiliser de nombreuxhead
s, donc unewhile
boucle est introduite et un peu de peaufinage avec les descripteurs de fichiers afin de passer à l'head
entrée des deux fichiers (fichierString.txt
comme fichier principal à traiter et lignes depuislength.txt
comme argument à-c
option) . L'idée est que l'avantage de la vitesse devrait provenir de ne pas avoir à chercher àString.txt
chaque fois qu'une commande commehead
oucut
est invoquée. Ilecho
suffit d'imprimer la nouvelle ligne après chaque itération.Combien il est plus rapide (le cas échéant) et l'ajout
>Entry_i
entre les lignes est laissé comme un exercice.la source
read -u 3
pour lire à partir du descripteur 3.bash
. La grande majorité des systèmes basés sur Linux ne sont pasbash
installés (pensez à Android et autres systèmes embarqués).bash
étant le shell le plus lent de tous, le passage à bash dégradera probablement les performances de manière plus significative que le petit gain que le passage deread <&3
àread -u3
pourrait apporter (ce qui en tout cas sera insignifiant par rapport au coût d'exécution d'une commande externe commehead
). Passer à ksh93 qui ahead
intégré (et celui qui prend en charge l'-c
option non standard ) améliorerait beaucoup plus les performances.head -c
(pour leshead
implémentations où cette option non standard est disponible) est un nombre d'octets, pas de caractères. Cela ferait une différence dans les paramètres régionaux multi-octets.Généralement, vous ne voulez pas utiliser de boucles shell pour traiter du texte . Ici, j'utiliserais
perl
:C'est une commande, qui lit (avec une mise en mémoire tampon beaucoup plus efficace que la
read
commande du shell qui lit un octet (ou quelques octets pour les fichiers normaux) à la fois) les deux fichiers une seule fois (sans les stocker en mémoire), tout comme va être plusieurs ordres de grandeur plus efficace que les solutions qui exécutent des commandes externes dans une boucle shell.(ajoutez l'
-C
option si ces nombres doivent être des nombres de caractères dans les paramètres régionaux actuels par opposition au nombre d'octets. Pour les caractères ASCII comme dans votre exemple, cela ne fera aucune différence).la source
$_
paramètres de sortie et d'entréeread
, mais cela réduit le nombre d'octets dans le script.bash
, 16 secondes avecPATH=/opt/ast/bin:$PATH ksh93
)).bash, version 4
production
la source
Et alors
awk
?Créez un fichier appelé
process.awk
avec ce code:Enregistrez-le et exécutez
awk -f process.awk lengths.txt string.txt
la source
PROCINFO
, ce n'est pas standardawk
, maisgawk
. Dans ce cas, je préférerais une autregawk
seule fonctionnalité, leFIELDWIDTHS
:awk -vFIELDWIDTHS="$(tr '\n' ' ' < lengths.txt)" '{for(i=1;i<=NF;i++)print">Entry"i ORS$i}' string.txt