Reading lines from a text file and creating a text file for each name on each line

#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

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 

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

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 =)