Today's article is a file management article...

KGIII

Super Moderator
Staff member
Gold Supporter
Joined
Jul 23, 2020
Messages
11,945
Reaction score
10,533
Credits
98,771
Have you ever wanted to copy a file to multiple directories? Well, you can do so with just one simple command. You can send a file to multiple directories at the same time pretty easily. In this case, we do it with the tee command.

This is also a 'short' article. I haven't done one of those in a while and this seemed like a fine time to do one. So, I did one...


Also, this time around I give some explicit instructions. If you follow those instructions, all things should become clear. That was the best way I could think of to explain this process. So, if you're new to this command (the tee command) you can learn by doing rather than learning by being told.

I think it worked well enough.
 


well heres one I didnt know oO

Code:
tee ./one/foo ./two/foo ./three/foo &

How does tee know to copy the file ./foo ..?

As this felt a bit hacky to me, heres chatgpt's answer to the problem (more characters to type though, however no backgrounding processes)

Code:
echo dir1 dir2 dir3 | xargs -n 1 cp source_file
 
actually you are wrong:

Code:
user@host:~/tmp$ echo foobar > foo
user@host:~/tmp$ mkdir one two three
user@host:~/tmp$ tee ./one/foo ./two/foo ./three/foo &
[4] 3126578
[4]+  Stopped                 tee ./one/foo ./two/foo ./three/foo
user@host:~/tmp$ cat one/foo
user@host:~/tmp$ # one/foo is empty, hence it was not copied but newly created

ChatGPT explains:

Why files are created even without visible input: As tee starts, even without explicit input piped to it, the act of specifying the file paths as arguments causes tee to open these files for writing. If these files do not exist, tee creates them. This is a characteristic of how file handling works in Unix-like systems; opening a file for writing generally involves creating it if it doesn't already exist.
 
Last edited:
Heres another weird version I found on some blog:

Code:
xargs -n 1 cp -v filename<<<"/dir1/ /dir2/ /dir3/"

I knew about the xargs one, which I would stick with I think. In bash scripts I commonly just use loops with an array to improve readability.
 
btw what you can do that with tee but a bit differently. This way isn't super efficient for large files but will do the trick for your common small textfile:

Code:
user@host:~/tmp$ echo foobar > foo
user@host:~/tmp$ mkdir one two
user@host:~/tmp$ cat foo | tee one/foo two/bar
foobar
user@host:~/tmp$ cat one/foo
foobar
user@host:~/tmp$ cat two/bar
foobar
 
well heres one I didnt know oO

Code:
tee ./one/foo ./two/foo ./three/foo &

How does tee know to copy the file ./foo ..?
The tee command creates the files foo, rather than copies them. If the file foo exists in the directory that the tee command is being run from, it is not that particular file named foo that will be moved to the specified directories, but rather, tee will create empty files with the name foo in the specified directories.

Testing to check this "file creation process" will show that if the file foo exists with some contents in the directory tee is executed from, those contents will not be moved into the specified directories, but rather, new files with the same name "foo" will be created.

Re-reading the article on linux-tips linked to in post #1, the following text needs amending:
Next, let’s make that file that we’ll copy to multiple directories:
The file is not actually copied, only the name of the file is copied in the example given. There's actually no need for the name of the file to be created before the tee command is run since tee will create the files the user names in the command.

@blunix quote from ChatGPT in post #3 captures the essence of tee, but doesn't quite differentiate the conflation of copy with creation which is the seminal point to be made here I think, and can be confusing with the use of same names as in the article.


Here is a test to make the point.

The directory from which this test is being conducted shows the contents containing file1 and 3 directories:
Code:
[tom@min ~]$ ls -F
file1  one/  three/  two/

The contents of file1:
Code:
[tom@min ~]$ cat file1
the quick brown fox jumps over the lazy dog

The tee command using the filename, file1:
Code:
[tom@min ~]$ tee ./one/file1 ./two/file1 ./three/file1
^C

The contents now of all directories which show all have a file named file1, the latter three as a result of the tee command:
Code:
[tom@min ~]$ ls -FR
.:
file1  one/  three/  two/

./one:
file1

./three:
file1

./two:
file1

Showing the contents of all the files named file1, shows that only the original file1 has the contents, and the other files named file1 in the directories specified by the tee command are new empty files of the same name:
Code:
[tom@min ~]$ cat file1
the quick brown fox jumps over the lazy dog
[tom@min ~]$ cat one/file1
[tom@min ~]$ cat two/file1
[tom@min ~]$ cat three/file1
[tom@min ~]$
 
Last edited:
The file is not actually copied, only the name of the file is copied in the example given. There's actually no need for the name of the file to be created before the tee command is run since tee will create the files the user names in the command.

Thanks everyone! I'll look at fixing it shortly!

I have people at the house currently, so it'll be a minute. We're going to have a pool (billiards) tournament.
 
You can actually use tee to copy file to multiple directories as follows:

Code:
$ tee ./one/foo ./two/foo ./three/foo < ./foo

$ cat one/foo
the quick brown fox jumps over the lazy dog

I looked it up in an article from cyberciti.biz.

Edit: I could be wrong, but I think the operator < makes tee read from file foo and write the contents of it into files we specify in the beginning of the command. We could've easily changed the command like so:

Code:
$ tee ./one/foo1 ./two/foo2 ./three/foo3 < ./foo

$ cat one/foo1
the quick brown fox jumps over the lazy dog

$ cat two/foo2
the quick brown fox jumps over the lazy dog

$ cat three/foo3
the quick brown fox jumps over the lazy dog

And now we have three files with different filenames but the same content as foo.
 
Last edited:
You can actually use tee to copy file to multiple directories as follows:

Code:
$ tee ./one/foo ./two/foo ./three/foo < ./foo

$ cat one/foo
the quick brown fox jumps over the lazy dog

I looked it up in an article from cyberciti.biz.

Edit: I could be wrong, but I think the operator < makes tee read from file foo and write the contents of it into files we specify in the beginning of the command. We could've easily changed the command like so:

Code:
$ tee ./one/foo1 ./two/foo2 ./three/foo3 < ./foo

$ cat one/foo1
the quick brown fox jumps over the lazy dog

$ cat two/foo2
the quick brown fox jumps over the lazy dog

$ cat three/foo3
the quick brown fox jumps over the lazy dog

And now we have three files with different filenames but the same content as foo.
yes, but thats pretty slow if you have large files
 
yes, but thats pretty slow if you have large files

Oh. Too bad. Now that I read your posts again, your command cat foo | tee one/foo two/bar is similar to what I wrote, I didn't notice :)
 

Members online


Top