-1

I have a file and my task is to read the file and generate a new file for each line. The name of newly generated file should come from the line content.

Example

The file has these two lines:

My name is hello world
My Name is not hello world

What I want is the following: File 1 should have 1 record and name of this file is fourth field of row which

What do you mean exactly?

First file should be named:

hello

File 2 should have 2nd record and name of the file should be 4 field of row which is not.

Here also. What do you mean exactly?

Second file should be named:

not
  • 1
    Hello and welcome to the U&L stack exchange site! Please review the Help Center to get information on how to best post on this site. To get to your question, what have you tried so far? You mention that you are using a UNIX system, could you include what shell or operating system you are using to help others know what tools you have available? Please edit your post to include this information. The more context you can add the better others will be able to help you! – kemotep Oct 12 '18 at 18:24
  • Hello @Animesh Saxena would you please check the answer below and let me know if this is what you need? Please re-edit the question for further clarifications and include the expected output. Thanks! – user88036 Oct 12 '18 at 18:27
  • @Animesh, Is this what you want? awk '{for(i=1;i<NF;i++) if(i == 4) print $0 > $i}' main where main is the name of your file. – Valentin Bajrami Oct 12 '18 at 19:00
  • @valentine this is not giving output – Animesh Saxena Oct 12 '18 at 19:10
  • @AnimeshSaxena It will create 2 files. Once again main is your filename containing those 2 lines – Valentin Bajrami Oct 12 '18 at 19:58
2
$cat mainfile
My name is hello world
My Name is not hello world

In bash

#!/bin/bash
cat mainfile | while IFS= read line ;do 

name=$(echo ${line} | awk '{print $4}')

echo "${line}" >> ${name} 
done

In csh

#!/bin/csh
foreach line ( "`cat mainfile`" )
set name = `echo ${line} | awk '{print $4}'`

    echo "${line}" >> $name
end

In order to create files for all the words in the mainfile

#!/bin/bash
cat mainfile | while IFS= read line ;do

     for word in $line; do

   echo "${line}" >> ${word} 
  done
done
  • 1
    Thank you for this it really helps. I used cut -d ‘,’ -f4 in place of awk I hope that should be okay. Second when I execute this with 4 lines in main file I am getting 3 rows in 1 file and 4 row in 1 file, please tell me if there is an issue – Animesh Saxena Oct 12 '18 at 18:50
  • But there is an issue as I need 4 files if there are 4 rows in main file. Please help me on this – Animesh Saxena Oct 12 '18 at 18:54
  • Are you using bash? for first file you need file named (My) (name) (is) (hello) (world) ? these are five not four please confirm? – user88036 Oct 12 '18 at 18:55
  • Yes I am using bash. For first file I need the whole row in new file and the name of the new file will be the fourth world of row which is hello and identifier as .txt – Animesh Saxena Oct 12 '18 at 19:01
  • 1
    Why do you touch then append? Why don't you just use the echo "$var" > "$file" which does CREAT and TRUNC? – glenn jackman Oct 12 '18 at 19:57
1

The lines of the file should be written to files whose names are taken from the fourth whitespace-delimited field. The word "record" refers to the a line. The word "column" is sometimes used in place for "field", and here one could have used the word "word" instead of "field". Both "record" and "field" are more generic than "line" and "column" (or "word"). In particular, a line is a newline-delimited record, and a "field" is often a whitespace-delimited column or word inside a record.

With awk:

awk '{ print >$4 }' <file.txt

This would run the print statement once for each line in the input file file.txt. The >$4 means that the output is redirected to a file named by the fourth field in the line. For the first line, this creates the file hello and for the second line, this creates the file not.

$ cat hello
My name is hello world
$ cat not
My Name is not hello world

If further lines were present in the file, each line would have been written to the files given by its fourth word. If two lines has the same fourth word, both lines would be written to the same file.

If a line has less than four words, this would generate an error.

awk uses newlines as the default record separator, and whitespace (tabs or spaces) as field delimiters, unless told otherwise.


Advanced awk-ness:

When doing this sort of redirection within an awk program, awk will keep the files opened until it exits, after reading all the data. Each open file requires one filedescriptor, and there's a limited number of these. If many files have to be written to, it's a good idea to close the files explicitly:

awk '{ print >>$4; close($4) }' <file.txt

Here, we open the output for appending to (rather than truncating and overwriting), write the current line to the file and close the file. When the same file is opened for output a second time (because field four happens to be the same for two or more lines), the data is appended. Had we used >$4, the new data would have overwritten the old. This is not a problem in the first program at the top as we never explicitly close the files.

The script (or whatever calls the awk program) would have to arrange for the output files to be empty or non-existing before running this, depending on circumstances.

Removing the files hello and not, and running the above command thrice:

$ rm hello not
$ awk '{ print >>$4; close($4) }' <file.txt
$ awk '{ print >>$4; close($4) }' <file.txt
$ awk '{ print >>$4; close($4) }' <file.txt
$ cat hello
My name is hello world
My name is hello world
My name is hello world
$ cat not
My Name is not hello world
My Name is not hello world
My Name is not hello world

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.