Reputation: 223
A file (foo.csv) contain entries (four columns) as follows:
A 5.3 3.2 1.2
A 2.1 3.4 6.7
A 3.4 2.1 5.6
A 0.4 2.2 4.2
In this file, I want to add the total number of lines in the first line followed by an empty line.
I want the output to be as follow.
4
A 5.3 3.2 1.2
A 2.1 3.4 6.7
A 3.4 2.1 5.6
A 0.4 2.2 4.2
Here is what I tried.
#to get the total number of lines in the file foo.csv
t=$((wc -l foo.csv | cut -d" " -f1))
#to add an empty line
sed -i "1i\\" foo.csv
#to insert the total number at the top; this works fine.
sed -i "1i $t" foo.csv
I need to do this for a bunch of files. So, script will be useful. The problem seems to be in sed -i "1i\\" foo.csv
. How to correct this?
Upvotes: 3
Views: 1296
Reputation: 58351
This might work for you (GNU sed):
sed -e '1e wc -l <file' -e '1H;1g' file
or to do everything in sed:
sed -e '1e sed "$=;d" file' -e '1H;1g' file
This uses the e
command to evaluate unix commands. Normally this is done using the e
flag to the s
command, but it can be used following an address, as in this situation.
An alternative, using a pipe:
wc -l <file | sed '1G' - file
or:
sed '$=;d' file | sed '1G' - file
Use the result of a wc or sed command as the first input file.
On retrospect, the easiest solution (although not the most efficient):
sed 'H;$!d;=;x' file
Which slurps the file into the hold space and inserts the number of lines and a blank line before printing out the hold space.
Upvotes: 0
Reputation: 67467
do the line counting with awk
as well.
$ awk 'NR==FNR{next} FNR==1{print NR-1 ORS}1' file{,}
or, with tac...tac
$ tac file | awk '1; END{print ORS NR}' | tac
Upvotes: 3
Reputation: 84521
You can do it quite simply using sed
with the 0,addr2
form (see man sed
under "Addresses") with general substitution, e.g.
$ sed '0,/^/s/^/4\n\n/' file
4
A 5.3 3.2 1.2
A 2.1 3.4 6.7
A 3.4 2.1 5.6
A 0.4 2.2 4.2
The sed
expression simply finds the first occurrence of the beginning of the line 0,/^/
and then substitutes the beginning of the line with 4\n\n
, using s/^/4\n\n/
Add the -i
option to edit-in-place (or -i.bak
to create a back of the original (e.g. file.bak
) while editing in place.
If you are interested in setting the number of lines, then you can simply get the lines with wc -l
using command substitution, e.g.
$ sed "0,/^/s/^/$(wc -l <file2)\n\n/" file2
8
A 5.3 3.2 1.2
A 2.1 3.4 6.7
A 3.4 2.1 5.6
A 0.4 2.2 4.2
A 5.3 3.2 1.2
A 2.1 3.4 6.7
A 3.4 2.1 5.6
A 0.4 2.2 4.2
(note: the use of double-quotes instead of single-quotes to allow expansion of the command substitution)
Upvotes: 1
Reputation: 133428
If you are ok with awk
could you please try following.
awk -v line=$(wc -l < Input_file) 'FNR==1{print line ORS} 1' Input_file
In case you want to add output into Input_file itself then append > temp_file && mv temp_file Input_file
to above code then.
Explanation: Adding explanation for above code too now.
awk -v line=$(wc -l < Input_file ) ' ##Creating variable line whose value is bash command wc -l to get line count for Input_file as per OP request.
FNR==1{ ##Checking if line number is 1 here then do following.
print line ORS ##Printing variable line here with ORS whose value is new line here.
} ##Closing FNR block here.
1 ##awk works on method of pattern and action mentioning 1 making condition TRUE and no action will make print to happen.
' Input_file ##Mentioning Input_file name here.
Upvotes: 2