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?
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?
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
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;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 after done makes read in the while loop condition read and store one line from in in line at each iteration; this way, touch "$line.txt" inside the loop will be expanded to the read line with .txt at the end.
– kos
Nov 22 '15 at 14:57
while read line; do touch "$line.txt"; done <in alone do the job? Where is the source file?
– kashish
Nov 22 '15 at 15:05
in is the source file, see the output of ls and cat in in the example.
– kos
Nov 22 '15 at 15:08
line variable know that it has to read from one line, and then from the next line?
– kashish
Nov 22 '15 at 15:56
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 =)
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
echo "" | tee file1 file2 file2 . But it does break if filenames contain spaces.
– Sergiy Kolodyazhnyy
Nov 22 '15 at 17:38