OVH Cloud OVH Cloud

Manipulation de fichiers

16 réponses
Avatar
Ph. Chantry
Bonjour,

Je voudrais ajouter des lignes au début d'un fichier.
Sauriez-vous comment faire sans passer par un fichier intermédiaire ?

Par exemple, si les lignes d'en-tête sont dans un fichier A, que je veux
insérer au début du fichier B, je voudrais pouvoir éviter de travailler
ainsi:

# cat A B > C
# mv C B

car cette façon de faire nécessite un espace disponible sur le disque égal à
volume de A + volume de B.

Je voudrais donc une commande qui permette de faire l'équivalent de :

# cat A B > B

Peut-être quelqu'un a-t-il déjà développé ça ?

Merci d'avance,
Philippe

10 réponses

1 2
Avatar
Nicolas Le Scouarnec
Par exemple, si les lignes d'en-tête sont dans un fichier A, que je veux
insérer au début du fichier B, je voudrais pouvoir éviter de travailler
ainsi:
Je voudrais donc une commande qui permette de faire l'équivalent de :
# cat A B > B
Peut-être quelqu'un a-t-il déjà développé ça ?


Si ca ne te dérange pas "d'écraser" A, tu peux faire:

cat B >> A

Ou encore:
<B >> A


Sinon, dans le genre pas propre
cat A B | (cat > B) (Le deuxieme cat est lancé après, dans un
sous shell, donc le fichier B est lu avant d'etre ecrasé.)

--
Nicolas Le Scouarnec
http://nlsn.free.fr (Slrnfr, Docs Linux/BSD, La grippe, ... )

Avatar
Andre Heinen
On Tue, 10 Feb 2004 16:28:16 +0000 (UTC), Nicolas Le Scouarnec
wrote:

cat A B | (cat > B) (Le deuxieme cat est lancé après, dans un
sous shell, donc le fichier B est lu avant d'etre ecrasé.)


Heu... Il me semble que les deux shells s'exécutent
simultanément. Je viens d'ailleurs d'essayer ceci:

$ sleep 10 | ( sleep 10 ) & ps -s
[1] 2076
PID TTY STIME COMMAND
380 con 18:01:47 /usr/bin/bash
1908 con 18:07:49 /usr/bin/sleep
2076 con 18:07:49 /usr/bin/sleep
2128 con 18:07:49 /usr/bin/ps

Les deux sleep s'exécutent donc simultanément.

--
Andre Heinen
My address is "a dot heinen at europeanlink dot com"

Avatar
Nicolas Le Scouarnec
cat A B | (cat > B) (Le deuxieme cat est lancé après, dans un
sous shell, donc le fichier B est lu avant d'etre ecrasé.)
Heu... Il me semble que les deux shells s'exécutent

simultanément. Je viens d'ailleurs d'essayer ceci:
Les deux sleep s'exécutent donc simultanément.


Effectivement, mais ce qui ce passe: ca marche , donc le fichier B est,
a priori, lu avant que le second processus le remplace par un fichier
vide. Il faudrait essayer avec de longs fichiers peut etre par contre.


--
Nicolas Le Scouarnec
http://nlsn.free.fr (Slrnfr, Docs Linux/BSD, La grippe, ... )


Avatar
Christophe Le Gal
On 2004-02-10, Ph. Chantry wrote:
Je voudrais donc une commande qui permette de faire l'équivalent de :
# cat A B > B


(echo '0r A' ; echo wq) | ed B

--
Christophe Le Gal

Avatar
JustMe
Nicolas Le Scouarnec wrote:


cat A B | (cat > B) (Le deuxieme cat est lancé après, dans un
sous shell, donc le fichier B est lu avant d'etre ecrasé.)


Heu... Il me semble que les deux shells s'exécutent
simultanément. Je viens d'ailleurs d'essayer ceci:
Les deux sleep s'exécutent donc simultanément.



Effectivement, mais ce qui ce passe: ca marche , donc le fichier B est,
a priori, lu avant que le second processus le remplace par un fichier
vide. Il faudrait essayer avec de longs fichiers peut etre par contre.




Ca ne réponds pas au pb de place disque de notre ami : B et sa "copie
fantome" coexistent....



Avatar
JustMe
Ph. Chantry wrote:

Bonjour,

Je voudrais ajouter des lignes au début d'un fichier.
Sauriez-vous comment faire sans passer par un fichier intermédiaire ?

Par exemple, si les lignes d'en-tête sont dans un fichier A, que je veux
insérer au début du fichier B, je voudrais pouvoir éviter de travailler
ainsi:

# cat A B > C
# mv C B

car cette façon de faire nécessite un espace disponible sur le disque égal à
volume de A + volume de B.

Je voudrais donc une commande qui permette de faire l'équivalent de :

# cat A B > B

Peut-être quelqu'un a-t-il déjà développé ça ?

Merci d'avance,
Philippe




Ca doit le faire en C :-)

Ca t'irait comme langage ? Si oui je ponds ca ce soir...





Avatar
Erwan David
Nicolas Le Scouarnec écrivait :

cat A B | (cat > B) (Le deuxieme cat est lancé après, dans un
sous shell, donc le fichier B est lu avant d'etre ecrasé.)
Heu... Il me semble que les deux shells s'exécutent

simultanément. Je viens d'ailleurs d'essayer ceci:
Les deux sleep s'exécutent donc simultanément.


Effectivement, mais ce qui ce passe: ca marche , donc le fichier B est,
a priori, lu avant que le second processus le remplace par un fichier
vide. Il faudrait essayer avec de longs fichiers peut etre par contre.


a priori rien du tout, vous n'avez *aucun* contrôle sur
l'ordonnancement, et il pourrait bien être écrasé par le deuxième
shell avant d'avoir été ouvert par le premier.

Vous jouez à la roulette russe là.



Avatar
JustMe
Attention c'est du QND (Quic 'n dirty) et j'ai pas faits de tests intensifs)

JM


#include <stdio.h>

main( int argc, char **argv)
{

FILE *a, *b;
char *buffer;
long size, buflen, bufptr, bsize;
int n;
int i;
int c;

if( argc != 3 )
{
fprintf( stderr, "Syntax is %s <a> <b> : insert file <a> at
beginning of <b>n", argv[0] );
exit(1);
}

a = fopen( argv[1], "r" );
if ( !a )
{
fprintf( stderr, "Can't open file %s for readingn", argv[1] );
exit(2);
}

b = fopen( argv[2], "r+" );
if ( !b )
{
fclose(a);
fprintf( stderr, "Can't open file %s for readingn", argv[2] );
exit(3);
}

fseek( a, 0L, SEEK_END );
size=ftell(a);
rewind(a);

fseek( b, 0L, SEEK_END );
bsize=ftell(b);
rewind(b);

buffer=(char *)malloc( size );
if ( !buffer )
{
fprintf( stderr, "Can't allocate memory for buffer. File %s may
be too big..n", argv[1] );
exit(4);
}

buflen = fread( buffer, 1, size, b );
rewind(b);
bufptr=0;

i = size;

while(i>0)
{
c= fgetc(a);
fputc( c, b);
--i;
}

bsize -= buflen;
while(bsize-- > 0 )
{
c = fgetc(b);
fseek( b, -1L, SEEK_CUR );
fputc( buffer[bufptr], b );
buffer[bufptr++] = c;
bufptr %= buflen;
}

i = buflen;
while(i)
{
fputc( buffer[bufptr], b );
++bufptr;
bufptr %= buflen;
--i;
}

fclose(a);
fclose(b);

exit(0);
}
Avatar
Ph. Chantry
Si ca ne te dérange pas "d'écraser" A, tu peux faire:

cat B >> A

Ou encore:
<B >> A


Sinon, dans le genre pas propre
cat A B | (cat > B) (Le deuxieme cat est lancé après, dans un
sous shell, donc le fichier B est lu avant d'etre ecrasé.)


Merci pour tes suggestions.

J'avais oublié de préciser que la taille de A est négligeable devant celle
de B, et que B est, en général, un assez gros fichier (500 Mo; je sais, avec
les disques qu'on vend aujourd'hui c'est ridicule, mais je dois vivre sur un
vieux serveur souvent à la limite de la saturation.).

Tes deux premières suggestions nécessitent un espace disponible égal à la
taille de B, ce qui ramène quasiment à mon problème initial.

La troisième solution marche avec de petits fichiers, mais plante avec un
gros B. Je n'ai pas cherché à trouver la cause de plantage. Le taille du
fichier manipulé reste en dessous des limites système données par ulimit -a.

Philippe

Avatar
Ph. Chantry
Je voudrais donc une commande qui permette de faire l'équivalent de :
# cat A B > B


(echo '0r A' ; echo wq) | ed B


Merci pour l'idée.
"ed" utilise des fichiers temporaires, créés sur disque; d'où retour au
problème initial.

Philippe


1 2