I need to remove a specific line number from a file using a bash script.
I get the line number from the grep command with the -n option.
I cannot use sed for a variety of reasons, least of which is that it is not installed on all the systems this script needs to run on and installing it is not an option.
awk is out of the question because in testing, on different machines with different UNIX/Linux OS's (RHEL, SunOS, Solaris, Ubuntu, etc.), it gives (sometimes wildly) different results on each. So, no awk.
The file in question is just a flat text file, with one record per line, so nothing fancy needs to be done, except for remove the line by number.
If at all possible, I need to avoid doing something like extracting the contents of the file, not including the line I want gone, and then overwriting the original file.
Given
dd
is deemed too dangerous for this in-place line removal, we need some other method where we have fairly fine-grained control over the file system calls. My initial urge is to write something in c, but while possible, I think that is a bit of overkill. Instead it is worth looking to common scripting (not shell-scripting) languages, as these typically have fairly low-level file APIs which map to the file syscalls in a fairly straightforward manner. I'm guessing this can be done using python, perl, Tcl or one of many other scripting language that might be available. I'm most familiar with Tcl, so here we go:Note on my particular box I have Tcl 8.4, so I had to load the Tclx package in order to use the ftruncate command. In Tcl 8.5, there is
chan truncate
which could be used instead.You can pass the line number you want to remove and the filename to this script.
In short, the script does this:
The file is edited exactly in place. No temporary files are used.
I'm pretty sure this can be re-written in python or perl or ... if necessary.
Update
Ok, so in-place line removal can be done in almost-pure bash, using similar techniques to the Tcl script above. But the big caveat is that you need to have
truncate
command available. I do have it on my Ubuntu 12.04 VM, but not on my older Redhat-based box. Here is the script:I would love to hear of a more generic (bash-only?) way to do the partial truncate at the end and complete this answer. Of course the truncate can be done with
dd
as well, but I think that was already ruled out for my earlier answer.And for the record this site lists how to do an in-place file truncation in many different languages - in case any of these could be used in your environment.
You can do it without grep using posix shell builtins which should be on any *nix.
Based on Digital Trauma's answere, I found an improvement that just needs grep and echo, but no tempfile:
Depending on the kind of lines your file contains and whether your pattern requires a more complex syntax or not, you can embrace the grep command with double quotes:
(useful when deleting from your crontab)
Since you have
grep
, the obvious thing to do is:But it sounds like you don't want to use any temporary files - I assume the input file is large and this is an embedded system where memory and storage are in short supply. I think you ideally need a solution that edits the file in place. I think this might be possible with
dd
but haven't figured it out yet :(Update - I figured out how to edit the file in place with dd. Also
grep
,head
andcut
are needed. If these are not available then they can probably be worked around for the most part:Run it thusly:
Suffice to say that
dd
is a very dangerous tool. You can easily unintentionally overwrite files or entire disks. Be very careful!Try ed. The here-document-based example below deletes line
2
fromtest.txt
If
n
is the line you want to omit: