remove last N lines from file bash - bash

i am trying to remove some text from a file, i need to find the line number using a string and then remove from that line to the end of the file.
i tried using sed and outputting to a new file using a string as a search term but it does not keep the lines, it just prints the whole file on one line, which isnt helpful as the rest of the script relies on line numbers.
my code so far is:
file=$(sed -ie '/<div class="col-wrapper">/,$d' < file1.txt)
echo $file > file.txt

You can just use inline editing in sed:
sed -i '/<div class="col-wrapper">/,$d' file1.txt
to save changes to file1.txt

This might work for you (GNU sed):
sed -i '/<div class="col-wrapper">/Q' file1.txt

Related

Delete all strings that do not contain any uppercase in Bash

I need to delete from a file all the words that do not contain any uppercase in bash.
I use the sed command but the output is the same as the input:
I tried sed 's/[^0-9]*//' file
Example input:
sjasd
ksaLK
asdn
Asdw
Output
ksaLK
Asdw
Could you please try following.
sed -n '/[A-Z]/p' Input_file
As per #PaulHodges's comment, once you are happy with results use sed -i .... option in above code to make changes in Input_file itself.
To make a file without those:
grep '[A-Z]' infile > outfile
This is a nondestructive way to check first. Then you could replace the old file with the new one.
If you really want to edit the existing file in place:
sed -i '/[A-Z]/!d' infile
This says to delete all lines that do not have a capital letter.

how to remove both first and last line of csv file using sed

I can remove the first line of csv file's starting with myfile and merge them using:
sed 1d myfile*.csv > myfile_merged.csv
I'd like to also remove the last line of the csv files.
I've tried:
sed 1d -i '$d' myfile*.csv > myfile_merged.csv
But get the error:
sed: can't read $d: No such file or directory
Problem is this command:
sed 1d -i '$d' myfile*.csv > myfile_merged.csv
You need not have an argument after -i (inline replacement) in sed otherwise it is treated as a SUFFIX to create a backup for inline replacement.
What you need is this gnu sed command:
sed -i '1d;$d' myfile*.csv
This will remove 1st and last line in each of the matched file and save it in place.
What you're probably trying to do is:
sed -e '1d' -e '$d' myfile*.csv > merged.csv
But this won't work, because it tells sed to remove the first and last line of ALL files, rather than EACH file. In other words, you'll strip the first line of the first file, and the last line of the last file ... and that's it.
To process each file individually, you probably need to process each file .. individually. :)
for f in myfile*.csv
sed -e '1d;$d' "$f"
done > merged.csv
Note that while this will run in bash, it's also POSIX compatible (both the shell and sed parts). And it does not care whether your input is CSV or any other format, as long as it can be parsed line by line using sed.

sed doesn't catch all sets of doubles

I've writted a sed script to replace all ^^ with NULL. It seems though that sed is only catching a pair, but not including the second in that pair as it continues to search.
echo "^^^^" | sed 's/\^\^/\^NULL\^/g'
produces
^NULL^^NULL^
when it should produce
^NULL^NULL^NULL^
Try with a loop to apply your command again to modified pattern space:
echo "^^^^" | sed ':a;s/\^\^/\^NULL\^/;t a;'
To edit a file in place on OSX, try the -i flag and multiline command:
sed -i '' ':a
s/\^\^/\^NULL\^/
t a' file
With GNU sed:
sed -i ':a;s/\^\^/\^NULL\^/;t a;' file
or simply redirect the command to a temporary file before renaming it:
sed ':a;s/\^\^/\^NULL\^/;t a;' file > tmp && mv tmp file
I really like SLePort solution, but since it is not working for you, you can try with (tested on Linux, not Mac):
echo "^^^^" | sed 's/\^\^/\^NULL\^/g; s//\^NULL\^/g'
It is doing the same as the former solution, but explicitly, not looping with tags.
You can omit the pattern in the second command and sed will use the previous pattern.

Bash script delete a line in the file

I have a file, which has multiple lines.
For example:
a
ab#
ad.
a12fs
b
c
...
I want to use sed or awk delete the line, if the line include symbols or numbers. (For example, I want to delete: ab#, ad., a12fs.... lines)
or in another words, I just want to keep the line which include [a-z][A-Z] .
I know how to delete number line,
sed '/[0-9]/d' file.txt
but I do not know how to delete symbols lines.
Or there has any easy way to do that?
To keep blank lines:
grep '^[[:alpha:]]*$' file
sed '/[^[:alpha:]]/d' file
awk '/^[[:alpha:]]*$/' file
To remove blank lines:
grep '^[[:alpha:]]+$' file
sed -E -n '/^[[:alpha:]]+$/p' file
awk '/^[[:alpha:]]+$/' file
grep works well too and is even simpler: just do the reverse: keep the lines that interest you, which are way easier to define
grep -i '^[a-z]*$' file.txt
(match lines containing only letters and empty lines, and -i option makes grep case-insensitive)
to remove empty lines as well:
grep -i '^[a-z]+$' file.txt
caution when using Windows text files, as there's a carriage return at the end of the line, so nothing would match depending on grep versions (tested on windows here and it works)
but just in case:
grep -iP '^[a-z]*\r?$'
(note the P option to enable perl expressions or \r is not recognized)
You can use this sed:
sed '/^[A-Za-z0-9]\+$/!d' file
(OR)
sed '/[^A-Za-z0-9]/d' file
$ awk '!/[^[:alpha:]]/' file.txt
a
b
c

Removing lines from multiple files with sed command

So, disclaimer: I am pretty new to using bash and zsh, so there is a chance the answer is really simple. Nonetheless. I checked previous postings and couldn't find anything. (edit: I have tried this in both bash and zsh shells- same problem.)
I have a directory with many files and am trying to remove the first line from each file.
So say the directory contains: file1.txt file2.txt file3.txt ... etc.
I am using the sed command (non-GNU):
sed -i -e "1d" *.txt
For some reason, this is only removing the first line of the first file. I thought that the *.txt would affect all files matching the pattern in directory. Strangely, it is creating the file duplicates with -e appended, but both the duplicate and original are the same.
I tried this with other commands (e.g. ls *.txt) and it works fine. Is there something about sed I am missing?
Thank you in advance.
Different versions of sed in differing operating systems support various parameters.
OpenBSD (5.4) sed
The -i flag is unavailable. You can use the following /bin/sh syntax:
for i in *.txt
do
f=`mktemp -p .`
sed -e "1d" "${i}" > "${f}" && mv -- "${f}" "${i}"
done
FreeBSD (11-CURRENT) sed
The -i flag requires an extension, even if it's empty. Thus must be written as sed -i "" -e "1d" *.txt
GNU sed
This looks to see if the argument following -i is another option (or possibly a command). If so, it assumes an in-place modification. If it appears to be a file extension such as ".bak", it will rename the original with the ".bak" and then modify it into the original file's name.
There might be other variations on other platforms, but those are the three I have at hand.
use it without -e !
for one file use:
sed -i '1d' filename
for all files use :
sed -i '1d' *.txt
or
files=/path/to/files/*.extension ; for var in $files ; do sed -i '1d' $var ; done
.for me i use ubuntu and debian based systems , this method is working for me 100% , but for other platformes i'm not sure , so this is other method :
replace first line with emty pattern , and remove empty lines , (double commands):
for files in $(ls /path/to/files/*.txt); do sed -i "s/$(head -1 "$files")//g" "$files" ; sed -i '/^$/d' "$files" ; done
Note: if your files contain splash '/' , then it will give error , so in this case sed command should look like this ( sed -i "s[$(head -1 "$files")[[g" )
hope that's what you're looking for :)
The issue here is that the line number isn't reset when sed opens a new file, so 1 only matches the first line of the first file.
One solution is to use a shell loop, calling sed once for each file. Gumnos' answer shows how to do this in the most widely compatible way, although if you have a version of sed supporting the -i flag, you could do this instead:
for i in *.txt; do
sed -i.bak '1d' "$i"
done
It is possible to avoid creating the backup file by passing an empty suffix but personally, I don't think it's such a bad thing. One day you'll be grateful for it!
It appears that you're not working with GNU tools but if you were, I would recommend using GNU awk for this task. The variable FNR is useful here, as it keeps track of the record number for each file individually, allowing you to do this:
gawk -i inplace 'FNR>1' *.txt
Using the inplace extension, this allows you to remove the first line from each of your files, by only printing the lines where FNR is greater than 1.
Testing it out:
$ seq 5 > file1
$ seq 5 > file2
$ gawk -i inplace 'FNR>1' file1 file2
$ cat file1
2
3
4
5
$ cat file2
2
3
4
5
The last argument you are passing to the Sed is the problem
try something like this.
var=(`find *txt`)
for file in "${var[#]}"
do
sed -i -e 1d $file
done
This did the trick for me.

Resources