Копирование вывода по SSH
Как скопировать вывод команды на удалённый SSH-сервер?
Ниже будут рассмотрены следующие варианты:
- cat,
- scp,
- sftp: curl и lftp.
Все они имеют смысл в том случае, если производимые командой данные имеют слишком большой размер и не помещаются на локальном диске, поэтому их необходимо сразу отправлять на удалённый сервер, без создания промежуточной локальной копии.
Наиболее распространённый пример: виртуальная машина с ограниченными ресурсами, выполняющая резервное копирование большой базы для отправки на удалённый сервер.
Классика жанра:
Наиболее известным методом является вызов cat на сервере:
локальная_команда | ssh remote_user@remote_host "cat - > /remote/file"
Однако как быть, если SSH-сервер предназначен только для копирования файлов и выполнение команд на нём ограничено через rssh, scponly, ForceCommand или authorized_keys?
Сначала разберёмся с scp:
Согласно официальной документации, scp работает только с обычными файлами и каталогами.
Попытка скопировать с его помощью /dev/stdout или именованный pipe выдаёт ошибку “not a regular file”.
Однако у scp существует недокументированный ключ “-t”:
$ scp -v /tmp/aa.txt localhost:/tmp/bb.txt Executing: program /usr/bin/ssh host localhost, user (unspecified), command scp -v -t /tmp/bb.txt OpenSSH_7.6p1 Ubuntu-4ubuntu0.3, OpenSSL 1.0.2n 7 Dec 2017 . debug1: Sending command: scp -v -t /tmp/bb.txt Sending file modes: C0664 33 aa.txt Sink: C0664 33 aa.txt date1.txt 100% 33 92.3KB/s 00:00 debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
Схема работы scp и всех прочих инструментов для передачи данных через SSH-транспорт (т.е. rsync, git и т.д.) примерно одинакова:
- локальный scp устанавливает ssh-сессию;
- запускает “scp -t /remote/file” на удалённой стороне;
- затем отправляет удалённому процессу scp служебный заголовок (права доступа, размер, локальное имя) и содержимое файла;
- которое тот читает из ssh-соединения и записывает на диск в /remote/file.
Т.е. запустив удалённый “scp -t” не локальной командой scp, а через ssh, и сформировав заголовок вручную, мы могли бы отправить данные так:
< echo "C0600 9999999999 test"; наша_команда; >| ssh remote_user@remote_host 'scp -t /remote/file.txt'
На практике данный способ малоприменим, потому что в заголовке требуется указать размер файла, а для вывода команды он заранее неизвестен.
Если указать заведомо большее число, то удалённый scp, во-первых, вернёт ошибку “broken pipe”, и во-вторых, не запишет последнюю часть принятых данных (сохранение производится блоками по 64 килобайта).
Неэлегантно обойти эту ошибку можно, добавив за вызовом команды отправку 64 килобайт нулей:
При этом придётся смириться, что (а) файлы на сервере станут занимать больше места за счёт хвостов с нулями, (б) перед дальнейшей обработкой файла этот хвост может потребоваться аккуратно отрезать, причём (в) не всегда имея возможность определить его точную длину.
Поэтому вариант с scp имеет смысл использовать в крайнем случае, когда запрещены и cat (см.выше), и sftp (см.ниже).
Забегая вперёд, следует отметить, что замена scp на curl без замены протокола с scp на sftp не помогает:
$ наша_команда | curl -k -sS -T - -u remote_user scp://remote.host/remote/file.txt Enter host password for user 'user1': *** curl: (25) SCP requires a known file size for upload
SFTP:
Если на сервере разрешён SFTP, то у нас появляется определённый выбор.
Например, поддержку SFTP имеет утилита cURL:
наша_команда | curl -k -sS -u username:password -T - sftp://remote.host/remote/file
- “-k” отключает проверку подлинности серверного ключа;
- “-sS” подавляет вывод информационных сообщений, оставляя только сообщения об ошибках;
- “-u” задаёт логин и пароль для подключения (если «:пароль» отсутствует, curl запросит его интерактивно);
- “-T -” читает данные для отправки со стандартного входа.
К сожалению, cURL собран с SFTP не во всех дистрибутивах. Проверяется это командой “curl -V”. Например, в CentOS 7 протоколы “sftp” и “scp” имеются в её выводе, а в Ubuntu 18.04 отсутствуют:
$ curl /tmp/aa.txt sftp://localhost/tmp/bb.txt curl: (3) malformed curl: (1) Protocol "sftp" not supported or disabled in libcurl
Однако в Ubuntu с поддержкой SFTP собрана другая замечательная утилита. Скрепный импортозамещённый вариант с её использованием будет выглядеть так:
наша_команда | lftp -u remote_user, -e "put /dev/stdin -o remote/file.txt" sftp://remote_host
- Для авторизации по SSH-ключу “remote_user” необходимо указывать через “-u”, а не внутри URL.
Вариант с “sftp://remote_user@remote_host” никакие настройки из ~/.ssh и /etc/ssh читать не станет. - Ключ “-u” используется со значением “remote_user,remote_password”.
Пароль указывать необязательно, но запятую удалять нельзя!
Подпишитесь на новые статьи:
Спасибо за Вашу заявку! В скором времени наш менеджер свяжется с Вами.
scp error: not a regular file
I am trying to copy a directory from my local machine to a remote machine. Here is the command I am using; sudo scp /run/media/orcacomputers/DataCabinet/fileBackups/centos6-root/etc/httpd/conf.d/ :root@ip/etc/httpd/conf.d What am I doing wrong here?
asked Mar 16, 2019 at 0:34
powerhousemethod powerhousemethod
179 1 1 gold badge 3 3 silver badges 16 16 bronze badges
2 Answers 2
You are missing the -r option that is required to copy a directory and its contents.
-r Recursively copy entire directories.
So your command would be:
sudo scp -r /run/media/orcacomputers/DataCabinet/fileBackups/centos6-root/etc/httpd/conf.d/ root@ip:/etc/httpd/conf.d
answered Mar 16, 2019 at 0:45
7,551 16 16 gold badges 32 32 silver badges 41 41 bronze badges
command not found
Mar 16, 2019 at 0:48
Which command is it saying is not found?
Mar 16, 2019 at 0:49
sudo: /run/media/orcacomputers/DataCabinet/fileBackups/centos6-root/etc/httpd/conf.d/: command not found [orcacomputers@orcainbox conf.d]$ sudo -r scp /run/media/orcacomputers/DataCabinet/fileBackups/centos6-root/etc/httpd/conf.d/ [email protected]:/etc/httpd/conf.d
Mar 16, 2019 at 1:01
You wrote sudo -r scp but it should be sudo scp -r
Mar 16, 2019 at 1:03
That’s a whole new problem now. Run it one more time with the additional -v option to see if it gives you more of a clue where it’s getting tripped up. Run sudo scp -rv /run/media/orcacomputers/DataCabinet/fileBackups/centos6-root/etc/httpd/conf.d/
Mar 16, 2019 at 1:17
move into localhost files from server
scp -r [email protected]:/var/www/html/foldername/ /var/www/html/foldername
17.5k 61 61 gold badges 30 30 silver badges 41 41 bronze badges
answered Feb 2, 2022 at 7:17
Deepak Jerry Deepak Jerry
1 1 1 bronze badge
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
scp gives «not a regular file» [closed]
Closed. This question is not about programming or software development. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 3 months ago .
The community reviewed whether to reopen this question 3 months ago and left it closed:
Original close reason(s) were not resolved
I have a problem when using scp on Linux, it says «not a regular file». I looked at other questions/answers about that, but I can’t find out what’s wrong. I wrote:
scp aa@aa:/home/pictures/file.fits .
to copy file.fits from aa@aa , /home/pictures to the current directory. I also tried without using /home/ , but it didn’t work neither. Do you understand what’s wrong?
19.8k 6 6 gold badges 65 65 silver badges 89 89 bronze badges
asked Apr 9, 2015 at 19:18
Fourmicroonde Fourmicroonde
621 1 1 gold badge 5 5 silver badges 3 3 bronze badges
Try: scp aa@aa:~/pictures/file.fits .
Apr 9, 2015 at 19:19
maybe the path is wrong and should contain your Linux user name. /home/
Apr 9, 2015 at 19:24
Tilda will be your best friend in this case :). Don’t extend your directory path in this case. And now that I am thinking of it, your command wont work anyways. If you were to add the whole directory, it would look something like: scp aa@aa:/home/aa/pictures/file.fits .
Apr 9, 2015 at 19:26
Log in with ssh ( ssh aa@aa ) and give command: file /home/pictures/file.fits and tell us what that says.
Apr 9, 2015 at 19:27
It will save you time and effort just by switching to rsync . Use rsync -azHvu aa@aa:/home/pictures/file.fits . . This will allow rsync to copy recursively and follow symlinks and show (verbose) what it is copying.
Apr 9, 2015 at 20:49
9 Answers 9
I just tested this and found at least 3 situations in which scp will return not a regular file :
- File is actually a directory
- File is a named pipe (a.k.a. FIFO)
- File is a device file
Case #1 seems most likely. If you meant to transfer an entire directory structure with scp use the -r option to indicate recursive copy.
answered Apr 9, 2015 at 20:11
Multimedia Mike Multimedia Mike
12.8k 5 5 gold badges 47 47 silver badges 62 62 bronze badges
It also occurs if you’re not awake yet and you have your source and destination inverted and you’re trying to copy a non-existent file from your destination to your source.
Dec 8, 2015 at 3:37
This implies reading stdin and writing stdout as in sftp -b <(echo get file /dev/fd/1)
Apr 5, 2017 at 9:49
I am facing the issue with symlinks too.
Nov 1, 2017 at 16:32
I’m trying to handle second case(in fact, I try to copy physical disk(like /dev/sda but actual name is a bit different. possible solution is to pipe disk to fifo then scp it to my host)
Oct 20, 2022 at 14:58
«/home/pictures/file.fits» must name an actual filesystem object on the remote server. If it didn’t, scp would have given a different error message.
I see that FITS is an image format. I suppose «/home/pictures/file.fits» is the name of a directory on the remote server, containing FITS files or something like that.
To copy a directory with scp , you have to supply the «-r» flag:
scp -r aa@aa:/home/pictures/file.fits .
answered Apr 9, 2015 at 20:15
23.9k 22 22 gold badges 82 82 silver badges 106 106 bronze badges
This really helped me To copy a directory with scp, you have to supply the «-r» flag
Jan 26, 2017 at 19:21
This resolved a problem I was having where trying to scp a UTM virtual machine file. or so I thought. .utm is a directory so I needed the ‘-r’.
Jun 28, 2023 at 14:18
One way this error can occur is if you have a space before the first path like below:
scp myUserName@HostName: /path/to/file /path/to/new/file ^
To fix, just take the space out:
scp myUserName@HostName:/path/to/file /path/to/new/file
answered Sep 3, 2015 at 22:32
3,621 3 3 gold badges 34 34 silver badges 53 53 bronze badges
By being teaching lots of people of basic sysadmin I must say in 90% cases it is because they are trying to copy directory without passing -r source
Just use -r flag. E.g to copy from remote to local:
scp -r root@IP:/path/on/server/ /path/on/local/pc
answered May 15, 2021 at 21:24
Ivan Borshchov Ivan Borshchov
3,185 5 5 gold badges 41 41 silver badges 62 62 bronze badges
It is possible that you are working with a directory/folder.
If this is the case, here is what you want to do:
- First, compress the folder. By running the command: zip -r name_of_folder.zip name_of_folder
- Then use the scp command normally to copy the file to your destination: scp path/to/name_of_folder.zip server:localhost:/path/to/name_of_folder.zip
- Enter your password if it prompts you for one.
- Unzip the name_of_folder.zip with this command: unzip name_of_folder.zip
That is it, you now have your folder in the destination system. By the way, this is for zip compression.
NOTE: If you are on Mac OS and you don’t want to see resource files such as _MACOSX, you may run:
**zip -r -X name_of_folder.zip name_of_folder**
Meaning the above command should be used instead of that in step 1 above.
Error using SCP: «not a regular file»
When copying a directory, you should use the -r option:
scp -r root@IP:/path/to/file /path/to/filedestination
12.8k 7 7 gold badges 59 59 silver badges 62 62 bronze badges
answered Oct 3, 2013 at 10:00
2,229 2 2 gold badges 12 12 silver badges 2 2 bronze badges
A regular file is a file that isn’t a directory or more exotic kinds of “special” files such as named pipes, devices, sockets, doors, etc. Symbolic links are not regular files either, but they behave like their target when it an application is accessing the content of the file.
You passed root@IP: as the source of the copy and /path/to/picture.jpg as the destination. The source is the home directory of the user root on the machine IP . This is useful as a destination, but not as a source. What you typed required to copy a directory onto a file; scp cannot copy a directory unless you ask for a recursive copy with the -r option (and it would refuse to overwrite an existing file with a directory even with -r , but it would quietly overwrite a regular file if the source was a regular file).
If /path/to/picture.jpg is the path on the remote machine of the file you want to copy, you need to stick the file name to the host specification. It’s the colon : that separates the host name from the remote path. You’ll need to specify a destination as well.
scp root@IP:/path/to/picture.jpg /some/destination
If you want to copy the local file /path/to/picture.jpg to the remote host, you need to swap the arguments. Unix copy commands put the source(s) first and the destination last.
scp /path/to/picture.jpg root@IP:
If you want to copy the remote file /path/to/picture.jpg to the same location locally, you need to repeat the path. You can have your shell does the work of repeating for you (less typing, less readability).
scp root@IP:/path/to/picture.jpg /path/to/picture.jpg scp /path/to/picture.jpg