0

I have a list of split CSV files. How can I copy the first CSV header to the rest of CSV files?

profiles00.csv profiles01.csv profiles02.csv profiles03.csv ...

This is what I have now but how do I send the output to new files or replace existing files?

find . -name \*.csv -print0 | xargs -0 -I {} -P 100 sed -e '1r {}' -e 'q' profiles00.csv

2

Here's one way to handle your particular problem:

find . -maxdepth 1 -type f -name "profiles*.csv" ! -name "profiles00.csv" -exec sed -i -e '1!b' -e 'R profiles00.csv' -e 'N' {} +

Written layed out in a multi-line manner as:

find . -maxdepth 1 \
    -type f \
    -name "profiles*.csv" ! -name "profiles00.csv" \
    -exec sed -i -e '1!b' \
                 -e 'R profiles00.csv' \
                 -e 'N' \
     {} +

to be read as: find utility shall

  • -maxdepth 1 => walk only in the current directory , normally it recurses down to all the way the lowest hierarchy.

  • -type f => while walking select the regular files only.

  • -name "profiles*.csv" ! -name "profiles00.csv" => out of all the regular files, select only thos who have profiles*.csv as their basenames AND filter out the "profiles00.csv" file since this is the header file.

  • -exec sed -i -e '1!b' -e 'R profiles00.csv' -e 'N' {} +

  • -i option => edit files in place GNU sed assumed

  • -e option => sed code follows

    • 1!b => don't touch the the non-first lines.

    • R profiles00.csv => read one line (since this is the first time, it'll be the first line) from the profiles00.csv file. So essentially the header is fished out of the profiles00.csv file. But not printed yet.

    • N => Read in the next line into the pattern space. this flushes out the read buffer and after that the actual pattern space is flushed out (lines 1,2) from the current file being operated upon by sed.

  • {} + will make find supply the multiple files it has selected in one fell swoop to the sed utility and GNU sed is capable of handling multiple files with the -i option. Specifically, the line numbers are reset for a new file read in.

≠================ Posix way ======

 LC_ALL=C  \
 find . ! -name . -prune -type f  \
     -name 'profiles??*.csv'      \
   ! -name 'profiles*[!0-9]*.csv' \
   ! -name 'profiles00.csv'       \
     -exec sh -c '
              shift "$1"
              head -n 1 < profiles00.csv > header
              for arg do
                 printf "0r header\\nw\\nq\\n" | ed -s "$arg"
              done
          ' 2 1 {} +

Here we dispense with sed and take recourse to ed.

  • 0r => will insert the contents of file mentioned, to the beginning of file being edited by ed.
  • w => will write to the file, thus freezing all the changes done.
  • q => will quit the ed editor.
1

You don't need xargs

Command :

find . -maxdepth 1 ! -name "profiles00.csv" -a -name "*csv" -exec sed -i "1s/^/$(head -1 profiles00.csv)\n/" {} \;

Here I am using find to select files and sed for in place editing

Explanation

find

  • maxdepth 1 - to only select files in the immediate directory and not in sub directory, if you want to edit files in sub directory too, you can remove this option
  • ! -name "profiles00.csv" -a -name "*csv" - to select all csv files but not profiles00.csv , here -a means and and ! means not

sed

  • -i - edit files in place
  • 1 - line addressing
  • s/^/$(head -1 profiles00.csv)\n/ - to replace beginning of file with the given text

head

  • -1 - to select first line
0

This is an untested pseudo-code sketch so it may not work, but I'd go about it something like (first backup your files so you don't overwrite them):

sed -i '1s/^/'`head -n1 profiles00.csv`'/' *.csv

explained

For more information on inserting into files:

https://stackoverflow.com/questions/9533679/how-to-insert-a-text-at-the-beginning-of-a-file

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.