Pull to refresh

Comments 16

Ну вы хоть скажите, что 0< == <, >file перенаправляет вывод в файл, затирая прошлое содержимое, а >>file добавляет в конец. А то в первом скрипте >, а дальше пошли >>

Прошу прощения, если что-то пропустил в тексте.
UFO just landed and posted this here
Хм, никогда двоеточием не пользовался — всегда пишу просто "> file"
Ого. Оба варианта оказались еще и POSIX. Это был приятный сюрприз.

Остался разве что аргумент в пользу читабельности ( cat /dev/null > myfile имхо наиболее очевиден).
Забив на указание граблей в статье (всёравно авторы перевода на это...)

Куда ещё очевиднее/читабельнее?
Redirection of output causes the file whose name results from the expansion of word to be opened for
writing on file descriptor n, or the standard output (file descriptor 1) if n is not specified. If
the file does not exist it is created; if it does exist it is truncated to zero size.

Просто помните это и всё, никаких «чёрнодырных-кошечек».
И ещё, выделеный жирным кусок произойдёт до cat /dev/null, так что условно вы этой командой лишние ресурсы жрёте и файл дважды очищаете, потому как I/O Redirection башем парсится до исполнения команды которая что-то в редирект пишет.
Наиболее очевиден, по-моему, cp /dev/null myfile. Этот вариант ещё и с sudo нормально работает в отличие от.

cp — это не bash builtin (как :), это отдельная программа (обычно отсюда), которая ещё может и отсутствовать (например, на embedded-устройствах или на Android-телефонах). Лучше приучать себя к lightweight решениям.

Обычно есть либо coreutils, либо аналог (у BSD вроде свои coreutils), либо busybox, у которого cp — вполне себе встроен, хотя и не shell builtin (у меня busybox делает clone() и запускает cp в потомке). Я лично вездесущности /dev/null уверен меньше, чем в том, что там, где стоит интерактивная POSIX‐совместимая оболочка есть и cp.

Ну вот, например, в Андроиде по умолчанию вплоть до 6-й версии был toolbox, где не было cp. В Гугл вот такие вот забавные ребята. Потому приходилось во всех сриптах для копирования использовался dd или cat перенаправлением ввода.

Команды «cp» не будет? Очень сильно сомневаюсь. Не нужно в крайности впадать.
UFO just landed and posted this here

Вроде там то же самое: сообщения об ошибках. Разве что их два, т.к. авторы почему‐то использовали не дефисоминус, а короткое тирэ, а текст ничего не говорит о том, что так и задумано, кроме множественного числа в «ошибках» (в оригинальном тексте, к слову, отсутствующего).

Я не критик, поэтому просто выражу благодарность за неплохой материал по башу.
Конечно же, бородатые гуру всегда укажут, где и что не так, но моё мнение об этом такое, что информации много не бывает. И особенно, когда изучаешь что-то неочевидное, никогда из одного источника ты ничему не научишься. Но прочитаешь 10 статей об одном и том же, но под другими ракурсами, и гораздо всё понятнее становится.
В случае с bash'ем это не так, так как из статьи в статью кочуют одинаковые неправильные способы его использования.

Неизвестно точно — стоит ли изучать bash вообще и писать скрипты на нём, но «почти работающие» решения, как правило, гораздо хуже отсутствия решения.
подскажите, почему не работает конструкция
cat title.html > title.html

почему файл становится пустым?

Потому что для того, чтобы stdout был перенаправлен в title.html оболочке нужно сначала настроить stdout, а потом запустить exec, чтобы заменить себя на cat: cat не может настроить сам себе stdout, о > title.html знает только оболочка, это не аргумент cat. Т.к. в данном случае вы попросили обрезать выходной файл, то последовательность действий выглядит примерно так:


  1. Оболочка клонирует себя, создавай дочерний процесс.
  2. В дочернем процессе настраивается stdout: открывается файл title.html (сразу с обрезанием), закрывается старый stdout, открытый файл становится новым stdout.
  3. С настроенным stdout дочерний процесс, бывший клоном оболочки, заменяет себя на cat.
  4. cat читает файл и выдаёт его в stdout, но файл‐то уже обрезан!

Точная последовательность и реализация зависит от оболочки, некоторые оболочки почему‐то даже предпочитают сохранить старый stdout куда‐то, заменить его на новый и только потом клонировать себя, после завершения же дочернего процесса закрыть новый stdout и вернуть старый на место. Если хотите посмотреть, как делает ваша оболочка, то запустите strace $SHELL -c 'cat title.html > title.html'.


Но в любом случае, вы не сможете получить отличного поведения никаким образом, пока > title.html не станет аргументом, который интерпретирует cat (точнее, ваша замена cat, потому как сам cat такого не умеет): оболочка просто не может обрезать файл после чтения (которое ещё и будет выполняться кусками вперемешку с записью), а использование временных файлов или чего‐то в этом роде противоречит спецификации конструкции перенаправления вывода.

Sign up to leave a comment.