I have a directory with tables in txt format, and I'd like to add the file name as the header of the second column, for example:


row_1 1 
row_2 0 
row_3 1  
row_4 1 
row_5 1 
row_6 1


rows  file_1
row_1  1 
row_2  0 
row_3  1  
row_4  1 
row_5  1

I was thinking in something like this

sed 1 's/top_row/$file_name/1' < "$file";
  • you wouldn't want to name all of the output files output.txt; are you expecting the files to be updated "in-place"? – Jeff Schaller Oct 10 '18 at 17:58
  • If any of the answers solved your problem, please accept it by clicking the checkmark next to it. Thank you! – Jeff Schaller Oct 21 '18 at 14:40

This writes out a line with rows file_1.txt and then cats out the entire file:

 echo "rows $file"; cat "$file"

If you want to drop the file extension from the output, as you've shown above, use basename:

 echo "rows $(basename $file .txt)"; cat "$file"
for file in ./file_*.txt
  awk 'NR==1 { print "rows", FILENAME }; 1' "$file" > temp && mv temp "$file"

Alternatively, with a sed that supports -i for in-place editing:

for file in ./file_*.txt
  sed -i "1i\
rows $file" "$file"
  • You should only use printf with an explicit format string to protect yourself from unknown characters in the filename: printf "rows\t%s\n", FILENAME (imagine the filename is foo%s.txt) -- then again print "rows", FILENAME is simpler. – glenn jackman Oct 10 '18 at 19:32
  • excellent point; thank, you, glenn -- I've incorporated it. – Jeff Schaller Oct 10 '18 at 19:48

Assuming file_*.txt would match all the files that you'd like to process, and that the files uses a tab character for delimiter:

for filename in file_*.txt; do
    { printf 'rows\t%s\n' "$filename"; cat "$filename"; } >$tmpfile &&
    mv "$tmpfile" "$filename"

This would iterate over the matching filenames, and for each file would output a line containing the header followed by the contents of the file itself into a temporary file which, if all that went ok, then replaces the original file.

Note that this modifies the original files. In your question you give one example and say that this should be outputted to output.txt, but it's unclear where to write the result for all the other files, so I went with this approach.


some incrutable perl, just for fun

perl -i -pe '$.==1&&do{($f=$ARGV)=~s/\..*?$//;$_="rows $f\n$_"};close ARGV if eof' *.txt

port-able and GNU valid sed, no i or a needed, done with s///.

file=TheFileName;  sed -i '1{h;s/.*/rows '"$file"'/;G}' "$file"

Expanded and explained, remove comments and use it in older seds.

sed -i '                           # start sed script.
        1                          # Only on the first line.
          {                        # Execute this commands.
            h                      # hold the first line.
            s/.*/rows '"$file"'/   # Transform to line to insert.
            G                      # append a newline first line in hold.
          }                        # That's all.
       ' "$file"                   # Script end and file name edited.
  • can be simplified a bit: sed '1{h;s/.*/rows '"$file"'/;G}' -- only add the header on line 1 and remove the loop. – glenn jackman Oct 11 '18 at 15:18
  • @glennjackman Thanks, yes: shorter, incorporated. – Isaac Oct 12 '18 at 1:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.