эффективный способ считывания первых 128 байт из сокета, но записи остальных непосредственно в файл

#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
  

но у этого метода есть два недостатка:

  1. все тело файла должно храниться в переменной BODY .
  2. это работает только для текстовых файлов.

Существует ли эффективный способ считывания первых 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; })