#linux #bash #networking
#linux #bash #сеть
Вопрос:
Я пытаюсь загрузить файлы из какой-либо службы следующим образом:
BODY="$(netcat "127.0.0.1" 61222 <<< "download|file_dir|file_name")"
SIGNATURE="$(echo -n "$BODY" | head -c 128)"
echo -n "$BODY" | tail -c 129 | dd of="$FILE_PATH" >amp; /dev/null
но у этого метода есть два недостатка:
- все тело файла должно храниться в переменной
BODY
. - это работает только для текстовых файлов.
Существует ли эффективный способ считывания первых 128 байт из сокета в переменную bash, но записи остальных непосредственно в файл?
Комментарии:
1.
head -c 128;
— head закрывает поток2. @KamilCuk нет, это не так.
3. Обратите внимание, что
echo -n "$var"
лучше заменить наprintf '%s' "$var"
; см. Раздел «ИСПОЛЬЗОВАНИЕ ПРИЛОЖЕНИЙ» спецификации POSIX дляecho
. В зависимости от того, какие именно переменные окружения активны во время запуска оболочки (установка флагов времени выполнения, которые также могут быть изменены во время компиляции или с помощью явного вызова кодаshopt
иset -o
),echo -n
on bash может печатать-n
на выходе; и последовательности с обратной косой чертой в вашей переменной могут выполняться даже без-e
.4. … также смотрите Отличный ответ в Unix amp; Linux на вопрос, почему
printf
лучше, чемecho
?5. Кстати, может ли подпись содержать символы NUL? (Если это так, вы не можете надежно сохранить его в переменной bash без кодировки base64 или аналогичной).
Ответ №1:
Может быть, используя bash
встроенную поддержку сокетов TCP? Файлы, подобные /dev/tcp/HOST/PORT
открытым сокетам, для данного хоста.
Грубо говоря (непроверенный код из-за отсутствия тестового сервера):
#!/usr/bin/env bash
exec 3<>/dev/tcp/127.0.0.1/61222 # Open a socket on descriptor 3
printf "%sn" "download|file_dir|file_name" >amp;3
read -r -N 128 -u 3 signature # Read 128 bytes from descriptor 3
cat <amp;3 >"$FILE_PATH"
exec 3<amp;- # Close the socket
Комментарии:
1. Эта же практика может быть использована с запущенным
netcat
coproc; это строго не требуется/dev/tcp
.2. @CharlesDuffy Зачем использовать
netcat
процесс, если вам это не нужно?3.
/dev/tcp
это опция времени компиляции; не все ее включают. Конечно, не всеnetcat
тоже устанавливают; настоящая причина моей заметки выше заключается в том, что текст ответа описывается/dev/tcp
как решение проблемы , когда оно действительно ортогонально проблеме — проблема может возникнуть или нет, независимоnetcat
от того, используется или/dev/tcp
нет.4. @Shawn как я могу проверить наличие ошибок в этом коде? как обычно используется
if [[ $? != 0 ]]
?5. @Shawn вместо
cat <amp;3 >"$FILE_PATH"
могу ли я использовать что-то вродеdd
, потому что мне нужна возможность указывать размер тела rest?
Ответ №2:
signature=$(nc .. | { head -c 128; cat > output_file; })
-c
Опция head
является нестандартной, хотя и поддерживается в head
реализации GNU coreutils. Чтобы сделать его более переносимым, head
его можно заменить на dd
:
signature=$(nc .. | { dd bs=128 count=1 2>/dev/null; cat > output_file; })