我需要将文件末尾的 -WOR 替换为 VWOR 。
我努力了
sed s/WOR/VWOR/g
但这在文件中有新的空白行之前不起作用。
所以我用了
( cat FileName && echo ) | sed 's/WOR/VWOR/g'
这有效。但由于 sed 正在读取整个文件,因此替换需要很长时间。
答案1
确保文件以新行结束。这是“文本文件”的要求。
[ -n $(tail -c1 FileName) ] && printf '\n' >> FileName
仅在需要时才会添加尾随换行符,因此多次使用也没有问题,而且速度非常快,因为它只检查最后一个字符。
然后,对(现在有效)最后一行 ($) 进行更改:
sed -ie '$s/WOR/VWOR/'
注意:此命令会将符号链接转换为真实文件。
答案2
好吧,我不知道如何用 sed/awk 或其他解决这个问题。这是用 C 语言编写的,速度应该很快:
/*
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;
}
答案3
您可以使用以下命令删除文件末尾的空行并在该文件中附加一些文本:
(sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' "${FILE_NAME}" | sed '$d' && echo "Hello") > "${NEW_FILE_NAME}"
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'
:这将删除文件末尾的所有空白行。
sed '$d'
:这将删除最后一行。
echo "Hello"
:这将附加文本。