I have text files which I'd like to divide up into different files based on arbitrary "tags" I put at the start of various lines.

Example text file:

I CELEBRATE myself, and sing myself,  
And what I assume you shall assume, 
For every atom belonging to me as good belongs to you.

#here I loafe and invite my soul, 
#here I lean and loafe at my ease observing a spear of summer grass.

#there My tongue, every atom of my blood, form'd from this soil, this air,
#there Born here of parents born here from parents the same, and their parents the same, 
#here I, now thirty-seven years old in perfect health begin, 
#here Hoping to cease not till death.

In this example I'd like to remove every line beginning with #here and append it onto a file called here.txt, every line beginning with #there into a file called there.txt, and leave every untagged line in the original file. (Ideally removing the #here #there tags in the process.)

I think this solution using awk might be helpful, but I am such a Unix noob that I don't know how to adapt this to my problem: How to split a file by using keyword boundaries

Any suggestions on how to proceed?

PS: I'm using the command line on OS X.

  • Do you only want to put #here lines into here.txt and #there lines into there.txt (so a line starting with #elsewhere, for example, would remain untouched) or do you just want to put #tag lines into tag.txt for all tags found in the input?
    – Ed Morton
    Jun 20, 2021 at 15:35

2 Answers 2


Your case is simpler than the linked case - you only need to look at each line (or "record" in awk parlance) and decide where to send it. So:

awk '/^#here/{print > "here.txt"; next} /^#there/{print > "there.txt"; next} {print}' input.txt

The remaining lines will be printed to standard output; portably, you can redirect that to a third file (rest.txt say) then rename it to the name of the original. If you have GNU awk, you can use the inplace module to modify the original file directly:

gawk -i inplace '/^#here/{print > "here.txt"; next} /^#there/{print > "there.txt"; next} {print}' input.txt

Using sed w command:

sed -n -e '/^#here/w here.txt' -e '/^#there/w there.txt' data

To preserve the row which not begin with the desired pattern:

sed -n -e '/^#here/w here.txt' -e '/^#there/w there.txt' -e '/^$/d;' -e '/^#/!w new_data.txt' data

This sed apply a match to the line and write it to the corresponding file.

If the line is untagged (/^#/!), and it is not empty(/^$/), then write the line to a file called new_data.txt, the file with all the untagged row.

If you like to keep the empty line remove the -e /^$/d; from the command line.

You must log in to answer this question.

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