I want to append two new columns in the beginning of a csv file using bash scripting in a way such that the first four letters of the filename are the values of the first column and the next two letters are the values of the second column. For instance, if my .csv filename is "exam_20", I want to have a new first column with all entries as "exam" and a new second column with with all entries as "20". Does anyone know how to achieve this in bash? Thanks in advance.

  • Please edit your question and add an example of your input file and your desired output.
    – terdon
    Jul 4, 2016 at 16:23

2 Answers 2


With awk:

#!/usr/bin/awk -f

BEGIN { OFS="," };

FNR==1 {

{ print c[1], c[2], $0 }

Or as a one-liner to run on the command-line or embed in a shell script:

awk -v OFS=',' 'FNR==1 {split(FILENAME,c,/[_.]/)}; {print c[1],c[2],$0}' *.csv

For each input file, this splits each FILENAME into an array c, using the character class [_.] as field separators. Fields 1 & 2 of array c are pre-pended to each line of the file.

Example output:

$ ./zsha.awk exam_20.csv 

Input data used in the example was:

$ cat exam_20.csv 
  • thanks for your solution; but the script that has to do this task is also doing other tasks also so I don't want to have an awk script!
    – zsha
    Jul 5, 2016 at 8:08
  • i wrote it as a one-liner then converted it to a stand-alone script for readability. to reverse, delete the #! and BEGIN lines and wrap the whole thing in single-quotes as awk -v OFS=',' '.....'. All the semi-colons are in-place where needed so you can even join up all the lines to make one long line. I'll edit my answer to give an example.
    – cas
    Jul 5, 2016 at 9:59

This code should do it, using sed, save it as an executable file and run with the full path to the source file as the first (and only) parameter. You can save the output to a new file if you like.

# check the file exists
[[ -s $FILE ]] || { echo "Can't locate file '$FILE', aborting" >&2; exit 1; }
# get the filename without directory
NAME=$(basename "$1")
# get the first 4 characters as FIRST
# get the 6th & 7th characters as SECOND
# are we good to go?
read -t30 -p "About to prefix '$FIRST,$SECOND,' to all lines in $FILE - ok (y/-): "
[[ $REPLY == "y" ]] || { echo "No changes made"; exit 0; }
# do it
sed "s/^/$FIRST,$SECOND,/" "$FILE"
exit 0

file exam_02:



  • Thanks for the explanation; I am trying to do this with a group of csv files in a folder say DIR=/home/Documents. I am using the for loop- for FILE in $DIR/*.csv; do (your answer) done but I am getting errors related to basename. Is this the correct approach?
    – zsha
    Jul 5, 2016 at 7:35
  • the NAME line in my code should read: NAME=$(basename "$1") (now amended) - think it should work after this change. The basename command needs a single parameter and because of lack of quotes with a path/filename containing spaces bash was passing it as multiple parameters. Oops.
    – gogoud
    Jul 5, 2016 at 10:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .