Можно ли \0
использовать в командной строке?
Фон
Для тестирования крайних случаев в GNU Parallel мне было интересно, все ли символы были правильно заключены в кавычки в командной строке. Большинство из них:
perl -e 'print pack ("c*",1..255,10)' | parallel -k echo | md5sum
d03484ca75b3e38be411198d66bf4611 -
perl -e 'print pack ("c*",1..255,10)' | md5sum
d03484ca75b3e38be411198d66bf4611 -
Но, \0
похоже, это сложно (здесь показано с помощью A\0B\n
):
perl -e 'print pack ("c*",65,0,66,10)' | wc -c
4 (A\0B\n)
perl -e 'print pack ("c*",65,0,66,10)' | parallel echo | wc -c
2 (A\n)
perl -e 'print pack ("c*",65,0,66,10)' | parallel --dry-run echo | wc -c
9 (echo A\0B\n)
perl -e 'print "echo ",pack ("c*",65,0,66,10)' | bash | wc -c
3 (AB\n)
Я могу как-то обосновать второй пример: \0
может быть интерпретирован как EOS, но тогда это также должно быть в случае примера 4. Пример 3 подчеркивает, что GNU Parallel не видит \0
как EOS, а передает его в bash
.
Можете ли вы объяснить, что происходит? Особенно меня озадачивает случай 4.
И что еще важнее:
Есть ли способ заключить \0
командную строку в кавычки, чтобы eg echo
ее увидел?
решение1
При выполнении команды список аргументов представляет собой список указателей на строки с символом NUL в конце, переданные execve()
системному вызову (точно так же, как переменные окружения, которые представляют собой другой список строк с символом NUL в конце, переданных системному вызову execve()
).
В результате аргументы и переменные окруженияказненкоманды не могут содержать символ NUL.
Исключением являются встроенные функции и функции в zsh
оболочке, аргументы которых могут содержать что угодно (они встроены, поэтому execve()
системный вызов не задействован).
Вы можете передавать данные с символами NUL через stdin (или любой другой файловый дескриптор) или в любом типе файла. Или некоторые команды понимают некоторую форму кодирования.
Например, совместимые с UNIX echo
реализации понимают \0
(два символа обратная косая черта и ноль) как означающие символ NUL. Некоторые другие реализации делают это только при передаче флага -e
.
Так:
echo '\0'
или:
echo -e '\0'
Может привести echo
к выводу символа NUL, за которым следует символ LF.
С zsh
,
echo $'\0'
передает символ NUL встроенному коду echo
.
/bin/echo $'\0'
Не будет работать, потому что /bin/echo
этоказнен, поэтому его аргумент не может содержать символ NUL.
Что касается вашего вопроса по пункту 4. Просто bash игнорирует эти символы NUL. Некоторые другие оболочки ведут себя по-другому.
$ printf 'e\0cho a\0b\n' | bash |& sed -n l
ab$
$ printf 'e\0cho a\0b\n' | ksh |& sed -n l
ksh: syntax error at line 1: `zero byte' unexpected$
$ printf 'e\0cho a\0b\n' | zsh |& sed -n l
zsh: command not found: e$
$ printf 'e\0cho a\0b\n' | rc |& sed -n l
line 1: warning: null character ignored$
line 1: warning: null character ignored$
ab$