21

Let's say I have a text file like:

john
george
james
stewert

with every name on a separate line.

I want to read the lines of this text file and create a text file for each name, like: john.txt, george.txt etc.

How can I do this in Bash?

kos
  • 41,378
levato
  • 213
  • 2
    Do you need the extension? There is no reason for text files to have a txt extension in Linux. – terdon Nov 22 '15 at 19:04

4 Answers4

19

In this particular case, where you only have a single word per line, you can also do:

xargs touch < file

Note that this will break if your file names can contain spaces. For such cases, use this instead:

xargs -I {} touch {} < file

Just for fun, here are a couple of other approaches (both of which can handle arbitrary file names, including lines with spaces):

  • Perl

    perl -ne '`touch "$_"`' file
    
  • Awk

    awk '{printf "" > $0}' file 
    

Note that on Linux and similar systems, the extension is optional for the vast majority of files. There is no reason to add a .txt extension to a text file. You are free to do so but it makes no difference at all. So, if you want the extension anyway, use one of:

xargs -I {} touch {}.txt < file
perl -ne '`touch "$_.txt"`' file
awk '{printf "" > $0".txt"}' file 
terdon
  • 104,404
18

#1 Using Bash + touch:

while read line; do touch "$line.txt"; done <in
  • while read line; [...]; done <in: This runs read until read itself returns 1, which happens when when the end of the file is reached; the input for read is read from a file named in in the current working directory instead of from the terminal due to the <in redirection;
  • touch "$line.txt": This runs touch on the expanded value of $line.txt, which is the content of line followed by .txt; touch will create the file if not existing and update its access time if existing;

#2 Using xargs + touch:

xargs -a in -I name touch name.txt
  • -a in: makes xargs read its input from a file named in in the current working directory;
  • -I name: makes xargs replace every occurence of name with the current line of input in the following command;
  • touch name: Runs touch on the replaced value of name; it will create the file if not existing and update its access time if existing;
% ls
in
% cat in
john
george
james
stewert
% while read line; do touch "$line.txt"; done <in
% ls
george.txt  in  james.txt  john.txt  stewert.txt
% rm *.txt
% xargs -a in -I name touch name.txt
% ls
george.txt  in  james.txt  john.txt  stewert.txt
kos
  • 41,378
7

Let's say I have a text file …

Let's say, I have an answer ;)

awk '{system("touch \""$0".txt\"")}' file

Waterproof also with spaces and with a suffix =)

A.B.
  • 92,275
7

AWK is also appropriate for this task:

testerdir:$ awk '{system("touch "$0)}' filelist

testerdir:$ ls
filelist  george  james  john  stewert

testerdir:$ awk '{system("touch "$0".txt")}' filelist                          

testerdir:$ ls
filelist  george.txt  james.txt  john.txt  stewert.txt
george    james       john       stewert

Another way, tee. Notice that this approach will break if a line contains more than one string in the filelist.

testerdir:$ echo "" | tee $(cat filelist)


testerdir:$ ls
filelist  george  james  john  stewert

Alternatively, </dev/null tee $(cat filelist) can be done as well, if you want to avoid piping

cp /dev/null approach (As I demonstrate this does work with filenames that contain spaces):

testerdir:$ cat filelist | xargs -I {}  cp /dev/null  "{}"                     

testerdir:$ ls
filelist  FILE WITH SPACES  george  james  john  stewert

testerdir:$ ls FILE\ WITH\ SPACES                                              
FILE WITH SPACES
  • 1
    @kos if each line in file contains exactly one string per line, then it creates a file per line. It's effectivelly the same as echo "" | tee file1 file2 file2 . But it does break if filenames contain spaces. – Sergiy Kolodyazhnyy Nov 22 '15 at 17:38