How to prepend filename to its content without a third file?

Hello,
Is possibly there a way to prepend the filename to its content without a third file? The reason is to add a header to each file contents to distinguish each other when they are pasted side-by-side.

sample.txt:

XLOC_001   0
XLOC_002   23
XLOC_003   4
XLOC_012   6

output (with the same name sample.txt):

sample.txt:

geneID     sample.txt
XLOC_001   0
XLOC_002   23
XLOC_003   4
XLOC_012   6

So far, I've tried:

for i in *.txt; do (echo "geneID    $i" ; cat $i) > ${i}; done

but got error: input file is output file
I'm aware of the solution is to use a tmp file, and rename it to the original name.

for i in *.txt; do (echo "geneID    $i" ; cat $i) > ${i}.tmp; mv ${i}.tmp ${i}; done

I am wondering if there is a way to do this job without the "tmp" file. The closest function I can think of is to add filename to its content within vim and :wq which does not require a third file name, but I have hundreds of files to modify.
Thanks!

Use ed:

for file in *.txt
do
     printf "%s\n" 1i "geneID  $file" . w | ed -s "$file"
done
1 Like

Thanks xbin!
This worked out to be exactly what I was looking for.
Could you please elaborate the first part of the pipe?

printf "%s\n" 1i "geneID  $file" . w 

I wish vim could be piped to the command line, and I am not familiar with ed at all.
Thanks again!

If you know vim , you know a lot more about ed than you think you do.

If you're in vim and you type in the command:

:1i

and then type in the two lines:

geneID  filename
.

What will happen. (It will insert the text geneID filename as a new line of text that will appear before the 1st line that was in the file before.)

And then what happens if you type in the command:

:w

(It will write the updated buffer back to the file you are editing.)

The ed (and ex ) utilities give you most of the commands that you type into vim that start with a colon, but do not need (or accept) the colon.

1 Like

Thanks Don!
Now I understand xbin's way using the old editor ed.
The left side of the pipe bugs me with a mixture of printf "%s\n" and other options for ed, as I can only understand this way:

printf "%b\n" "1i\ngeneID\t$file\n.\nw" | ed -s $file

which seems working too.
When I learned vim, sometime I wished there is similar function as piped to receive stdout.

EDIT: I am so naive! Experts have dug way deeper than what I thought, like my this question. ed, ex, and new vipe in moreutils package.

Thanks again!