Je veux diviser et GZip un fichier volumineux, et cette réponse semblait être ce que je cherchais, et cela me semblait une manière très utile de faire des choses auxquelles je n’avais jamais pensé, alors je voudrais les généraliser; le seul problème est: cela ne semble pas fonctionner.
Dites que je veux diviser mon entrée et la traiter plus avant (je sais split
mais je veux le diriger directement dans mon script!)
Cette utilise read
lire une ligne dans une variable
#!/bin/bash
printf " a \n b \n c \n d " |
for ((i = 0 ; i < 2 ; i++)) ; do
echo "<< $i >>"
for ((j = 0 ; j < 2 ; j++)) ; do
read l
echo "$l"
done
done
Il imprime
<< 0 >>
a
b
<< 1 >>
c
d
Ce qui est presque ce que je veux, mis à part le fait qu'il réduit les espaces au début et à la fin (et peut-être modifie la ligne d'une autre manière? Cela fonctionnera-t-il avec du contenu codé UTF-8 arbitraire?) modifier résolu
Et j'imagine que cela pourrait être assez lent. modifier Le comparé: au moins 3000x plus lent.
Alors j'ai essayé de le faire passer à travers head
(Je reçois le résultat en utilisant awk
comme le suggère la réponse, cela ne semble pas faire autre chose)
#!/bin/bash
printf " a \n b \n c \n d " |
for ((i = 0 ; i < 2 ; i++)) ; do
echo "<< $i >>"
head -n 2
done
Qui imprime
<< 0 >>
a
b
<< 1 >>
Et arrête parce que head
ferme apparemment son entrée en sortie. Je n'ai pas trouvé de programme qui ne le fasse pas, et peut-être est-il réellement imposé par le système? (Je suis sous OS X)
En utilisant head -n 2 <&0
qui (selon les bash docs) copie le descripteur de fichier ne fonctionne pas non plus.
Dois-je utiliser un tuyau nommé? Y a-t-il une incantation pour faire ce travail?
echo "..$l.."
pour voir ce qui a été stocké dans l comme écho ignore les blancs de début et de fin.read
le dépouille,echo ".$l."
empreintes.a.
. Je pense que le shell supprime les espaces lors de la division des arguments,l=" a "; echo $l
empreintesa
maisl=" a "; echo "$l"
affiche les espaces `a`. (read
peut également saisir des espaces et remplir plusieurs variables, c’est probablement pour cela)read l
.Réponses:
Le problème ici n'est pas exactement ça
head
ouawk
sont "fermer l'entrée". Ils n'ont pas le choix. tout programme ferme son entrée quand il se termine, et cela est imposé par le système d'exploitation.Le problème est que l'entrée standard est un canal et que les programmes effectuent des lectures en mémoire tampon. Il n'y a aucun moyen de ne pas lire à partir d'un tube, donc les données contenues dans le readahead ont disparu. Si au lieu d'utiliser un canal, vous utilisez un fichier, vous verrez probablement que cela fonctionne bien:
Au moins, cela fonctionne bien sur Ubuntu. Vous pouvez le faire fonctionner avec un tuyau si vous désactivez la mise en mémoire tampon - mais cela ralentira probablement les choses. Voici un petit programme en C qui désactive la mise en mémoire tampon, puis répète son caractère entrée par caractère jusqu'à ce qu'il consomme le nombre de lignes demandé:
Cela a bien fonctionné pour moi (encore sur Ubuntu - et vous devez le compiler avec
-std=c99
ou-std=c11
afin que le compilateur ne se plaint pas). C'est vrai que le programme n'appelle pasfclose(stdin)
, mais ajouter ne fera aucune différence. D'autre part, supprimer l'appel àsetvbuf
va probablement vous ramener au symptôme que vous avez observé avechead
. (Et cela fera aussi que le programme fonctionne lot plus rapide.)Si vous aviez GNU
split
au lieu de la version BSD livrée avec OS X, vous pourrez utiliser l’utile--filter=COMMAND
une syntaxe qui fait à peu près exactement ce que vous voulez; au lieu de créer des fichiers fractionnés, il dirige chaque section de fichier vers un appel de la commande spécifiée (et définit la variable d'environnement$FILE
au nom de fichier attendu).la source
--filter
; c'est le genre de flexibilité que je cherchais.En spécifiant une variable à
read
vous lui ordonnez de séparer les mots. Ne faites pas ça, et les espaces resteront intacts:Sortie:
Cela semble être très simple, mais en fait, vous avez posé une très bonne question car cette fonctionnalité n’est pas expliquée clairement dans l’homme.
P. S. Je voudrais utiliser un
-r
flag (ne pas traiter\
comme échappé) pourread
également.la source
$REPLY
. L'alternative que j'ai vue estIFS= read var
. Cependant, en utilisantread
dans une boucle bash est incroyablement lent (1e3 lignes prennent 6,3 s) par rapport àhead
(1e6 lignes prend 1,8 s), ce qui n’est utile que pour les petits fichiers.Mais si vous voulez écrire un script autonome pour exploiter des fichiers volumineux, AWK conviendrait beaucoup mieux que Bash pour des raisons d'efficacité. Un one-liner:
La même chose qu'un script:
La même chose qu'un script Bash:
Un repère avec un million de lignes:
Vous voyez, pourquoi Bash n'est pas un interprète préférable ici.
la source