Вопрос или проблема
Я пишу некоторый код приложения, который используется для выполнения команд оболочки Linux, а затем логирует детали команд в SQL базе данных. Это включает вывод STDOUT + STDERR (отдельно).
После выполнения команды и если процесс ничего не вывел… может ли быть какая-либо причина оставить поля STDOUT/STDERR равными NULL, а не задать их как пустые строки?
Чтобы переформулировать вопрос: есть ли технически какая-либо разница между этими двумя случаями?
- Процесс, который ничего не выводит в STDOUT
- Процесс, который выводит пустую строку в STDOUT (и ничего больше)
И снова переформулируя вопрос… имеет ли смысл сделать эти столбцы NOT NULL в SQL?
В канале (std-err/out) нет концепции пустой строки, это просто “нет вывода”;
> printf ''
> printf '' | xxd
в то время как null – это нечто
> printf '\0'
> printf '\0' | xxd
00000000: 00
Противоположное верно в базе данных, и чем меньше, тем лучше, поэтому пусть ваши скрипты будут молчаливыми (пустая строка), а ваша БД – пустой (null).
Не уверен, что понимаю вопрос, но:
Запись в stdout выполняет:
write(1, memory_address, length)
Что записывает length байтов, сохраненных по адресе memory_address, в дескриптор файла 1 (1 для stdout, 2 для stderr). Например, в echo test
, echo
(или оболочка, если echo
встроен) выполняет write(1, "test\n", 5)
.
Хотя это немного нелепо, вы можете вызвать системный вызов write()
с длиной 0.
При этом:
write(1, address, 0)
По крайней мере на GNU/Linux, системный вызов все равно проверяет, что дескриптор файла был открыт в режиме записи или чтения+записи и что адрес является допустимым адресом (хотя он не обязательно должен быть читабельным). Если stdout является разорванной трубой, я не вижу, чтобы это вызвало получение сигнала SIGPIPE.
Таким образом, выполнение write()
нулевого размера не является строго эквивалентным тому, чтобы вообще ничего не писать, поскольку это может вызвать ошибки.
На практике, я замечаю, что большинство команд избегают write()
, если могут.
Я обнаружил, что echo -n
(стиль Unix V7) или echo '\c'
(стиль SysIII) и printf ''
не делают никаких вызовов write()
во всех реализациях, которые я пробовал. Функции stdio (fputs()
/printf()
/fwrite()
… не выполняют никаких write()
, когда вы просите их записать пустую строку).
Чтобы выполнить запись нулевой длины, вы можете попробовать:
perl -e 'syswrite(STDOUT, "")'
Или
python -c 'import os; os.write(1, "")'
Что является «сырыми» интерфейсами в этих интерпретаторах к write()
.
Пример:
$ strace -e write /bin/echo -n
$ strace -e write python -c 'import os; os.write(1, "")'
write(1, "", 0) = 0
$ python -c 'import os; os.write(1, "")' >&-
Traceback (most recent call last):
File "<string>", line 1, in <module>
OSError: [Errno 9] Bad file descriptor
$ python -c 'import os; os.write(1, "")' 1< /dev/null
Traceback (most recent call last):
File "<string>", line 1, in <module>
OSError: [Errno 9] Bad file descriptor
$ printf '%s\n' '#include <unistd.h>' 'main(){write(1,(char*)-1,0);}' | strace -e write tcc -run -
write(1, "", 0) = -1 EFAULT (Bad address)
$ printf '%s\n' '#include <unistd.h>' 'main(){write(1,(char*)0,1);}' | strace -e write tcc -run -
write(1, NULL, 1) = -1 EFAULT (Bad address)
$ printf '%s\n' '#include <unistd.h>' 'main(){write(1,(char*)0,0);}' | strace -e write tcc -run -
write(1, NULL, 0) = 0
Ответ или решение
Вопрос, касающийся различий между пустой строкой и значением NULL в контексте вывода стандартного вывода (STDOUT) и стандартного вывода ошибок (STDERR), действительно важен, особенно при разработке приложений, которые взаимодействуют с командной строкой и сохраняют данные в базы данных.
Технические различия между пустой строкой и NULL
-
Определения:
- Пустая строка: Это строка, которая существует и имеет длину 0. Она представляется как
""
в большинстве языков программирования. - NULL: Это специальное значение, указывающее на отсутствие данных. Оно не является строкой и обычно обозначает, что переменная либо не была инициализирована, либо не содержит значимой информации.
- Пустая строка: Это строка, которая существует и имеет длину 0. Она представляется как
-
Работа с выводом:
- Если процесс не генерирует вывод (т.е. ничего не пишет в STDOUT или STDERR), этот момент эквивалентен концепции отсутствия вывода. В системном вызове
write()
процесс может не выполнять никаких действий, что в конечном итоге приводит к тому, что вывод вообще не происходит. - В отличие от этого, если процесс явно пишет пустую строку в STDOUT, то выполняется системный вызов
write(1, "", 0)
, который может приводит к выполнению минимальных проверок, но фактически не создает никакого вывода.
- Если процесс не генерирует вывод (т.е. ничего не пишет в STDOUT или STDERR), этот момент эквивалентен концепции отсутствия вывода. В системном вызове
SQL и база данных
В контексте вашей базы данных, выбор между использованием NULL и пустой строкой зависит от того, как вы хотите интерпретировать эти значения:
-
NULL:
- Подразумевает отсутствие данных.
- Это может быть полезно, когда нужно различить "вывод отсутствует" и "вывод есть, но он пуст".
-
Пустая строка:
- Указывает на то, что данные существуют, но в данный момент являются пустыми.
- Подходит, если вы хотите отразить, что процесс выполнился, но вывод не содержал полезной информации.
Решение для столбцов базы данных
Решение о том, делать ли столбцы для STDOUT и STDERR NOT NULL, зависит от потребностей вашей системы:
- Если ваша система должна различать отсутствие вывода и пустой вывод, разумно использовать NULL для обозначения отсутствия результатов.
- Если же отсутствие информации не имеет значения, и вы хотите упростить логику обработки, вы можете установить пустую строку как значение по умолчанию.
Заключение
Что касается вашего приложения, рекомендуется использовать NULL для обозначения того, что вывод не был сгенерирован, и пустые строки для случаев, когда вывод был, но не имел содержимого. Это позволит избежать путаницы и делать четкое различие между "ничего нет" и "вывод есть, но он пуст".
Таким образом, решение, нужно ли использовать NOT NULL в вашей базе данных, должно основываться на том, какую информацию вы хотите сохранить и как будете обрабатывать эти данные в вашем приложении.