Bem, eu não sei como resolver isso com sed / awk ou outro. Aqui está em C e deve ser bem rápido:
/*
by Hans Schou <[email protected]> 2016
Use on your own risk.
vim: ts=4 :
gcc -o replacelastline replacelastline.c && ./replacelastline WOR VWOR Filename V
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define SEARCH 1
#define REPLACE 2
#define FILENAME 3
#define VERBOSE 4
int main(int argc, char *argv[]) {
if (FILENAME >= argc) {
printf("Error, too few args. Only found %d.\n", argc);
return EXIT_FAILURE;
}
printf("argc %d.\n", argc);
int V = 0;
if (VERBOSE <= argc) {
V = 'V' == argv[VERBOSE][0] ? 1 : 0;
printf("Verbose: %d\n", V);
}
if (V) {
printf("argv[SEARCH]: %d %s\n", strlen(argv[SEARCH]), argv[SEARCH]);
printf("argv[REPLACE]: %d %s\n", strlen(argv[REPLACE]), argv[REPLACE]);
printf("argv[FILENAME]: %s\n", argv[FILENAME]);
printf("Open file: %s\n", argv[3]);
}
size_t newFileSize = 0;
FILE *fp = fopen(argv[FILENAME],"r+");
if (NULL == fp) {
fprintf(stderr, "Error open file: %s\n", argv[FILENAME]);
return EXIT_FAILURE;
} else {
char inpBuf[8192];
/* Seek to end-of-file minus buffer size */
if (0 == fseek(fp, -sizeof(inpBuf), SEEK_END)) {
/* Read buffer with last part of file */
if (sizeof(inpBuf) != fread(&inpBuf, 1, sizeof(inpBuf), fp)) {
fprintf(stderr, "Error, could not read %d bytes from '%s'\n", sizeof(inpBuf), argv[FILENAME]);
return EXIT_FAILURE;
} else {
/* In the inpBuf, search backwards where the last line start */
int i = sizeof(inpBuf)-1-1; /* one extra minus-1 if last char is '\n' */
while (i && '\n' != inpBuf[i-1]) {
--i;
}
newFileSize = ftell(fp) - sizeof(inpBuf) + i;
if (V) printf("Last line number of chars: %d\n", sizeof(inpBuf)-i);
if (V) printf("The line: '%*.*s'\n", 10, sizeof(inpBuf)-i, &inpBuf[i]);
/* Seek back in the file to where the last line starts */
if (0 == fseek(fp, -(sizeof(inpBuf)-i), SEEK_END)) {
if (V) printf("Pos start last line: %d\n", ftell(fp));
char outBuf[sizeof(inpBuf)];
int o = 0;
/* Read inpBuf and copy to outBuf. If SEARCH found replace with REPLACE */
while (sizeof(inpBuf) > i) {
if (0 != strncmp(&inpBuf[i], argv[SEARCH], strlen(argv[SEARCH]))) {
outBuf[o] = inpBuf[i];
++i;
++o;
} else {
memcpy(&outBuf[o], argv[REPLACE], strlen(argv[REPLACE]));
i += strlen(argv[SEARCH]);
o += strlen(argv[REPLACE]);
}
}
newFileSize += o;
if (V) printf("New line: '%*.*s'\n", o, o, &outBuf);
size_t bytesWritten = fwrite(&outBuf, 1, o, fp);
if (o != bytesWritten) {
fprintf(stderr, "Error, should write %d bytes, but wrote %zu bytes.\n", o, bytesWritten);
return EXIT_FAILURE;
}
}
}
}
fclose(fp);
/* if file should be smaller than before then truncate */
if (newFileSize && strlen(argv[SEARCH]) > strlen(argv[REPLACE])) {
if (V) printf("New file size: %zu\n", newFileSize);
truncate(argv[FILENAME], newFileSize);
}
}
return EXIT_SUCCESS;
}