Я знаю основы этих трех. И причина, по которой cat < file > file очищает содержимое файла. Но я не понимаю, почему cat < file >> file вместо того, чтобы записывать содержимое дважды, объединяет содержимое как в бесконечном цикле while.
2 ответа
Ну, мой cat (в Kubuntu) говорит, что input file is output file и выходит. Я понимаю, что ваш cat не такой умный (или как ленивый).
То, что вы наблюдаете, довольно легко объяснить. cat читает и пишет кусками. Предположим, что первый блок не достигает конца файла (EOF), а его содержимое объединяется в конце того же файла. Чтение cat продвинулось на некоторое количество байтов, но конец файла "сместился" на ту же величину. По сути, cat снова так же далека от EOF, как и в начале. И это продолжается и продолжается и продолжается.
Как будто вы бежали, и на каждые 100 метров финишная черта была удалена еще на 100 метров от вас. Вы никогда не достигнете этого, и пройденное расстояние будет расти без конца.
Если исходное расстояние составляет 100 метров или меньше. В этом случае вы доберетесь до финиша до того, как он переместится. Аналогично, cat может закончить, если файл достаточно мал, но я действительно в этом сомневаюсь. Я ожидаю, что cat "знает", что она попала в EOF, только когда она пытается прочитать снова и может прочитать 0 байтов, не более. Это означает, что он уже читает до EOF на предыдущем шаге, когда он читает более 0 байтов. Но в вашем случае, если он прочитал больше 0 байтов на предыдущем шаге, то файл сразу же вырос после того, как все еще есть данные для чтения.
Я предсказываю два случая, чтобы ваша cat остановилась:
- когда файл пуст (длиной 0 байт),
- если файл не существует и вы измените порядок перенаправлений (например,
cat >> file < fileбудет работать,cat < file >> fileвыдаст ошибку; это потому, что перенаправления "обслуживаются" слева направо,>>создает файл, если необходимо,<требует, чтобы файл существовал).
В общем случае использование одного и того же файла с перенаправлением stdin и stdout (или / и stderr) в одной команде вызывает проблемы. Тем не менее, если вам нужно сделать это, есть утилита sponge (например, в пакете moreutils для Ubuntu, Debian).
spongeчитает стандартный ввод и записывает его в указанный файл. В отличие от перенаправления оболочки, губка впитывает весь свой ввод перед открытием выходного файла. Это позволяет сжимать конвейеры, которые читают и записывают в один и тот же файл.Если выходной файл не указан,
spongeвыводит на стандартный вывод.
Вместо cat < file >> file запустите sponge < file >> file . Он будет делать то, что вы ожидали от cat (если, я думаю, файл не настолько велик, чтобы истощать ваши ресурсы, пока вы поглощены).
Другой способ - < file cat | cat >> file . Из-за буферизации между двумя cat s первый действительно ударит EOF и завершит работу, прежде чем второй расширит файл, если файл достаточно мал . Повторите эту команду несколько раз, начиная с небольшого (но не пустого) файла, и файл со временем станет достаточно большим, чтобы заставить команду вести себя как ваша оригинальная команда с одним cat . Примечание < file cat | unbuffer cat >> file избавляется от буфера и зацикливается даже для очень маленьких файлов.
Ну, в основном это работает следующим образом:
>используется для переопределения содержимого файла. Например:echo "HELLO WORLD" > file.txt.
>>используется для добавления содержимого в файл. Например:echo "New line" >> file.txt.
<вы можете использовать файл в качестве входных данных и перенаправить в другой файл. Например:cat < file.txt > file2.txt. Практическим примером являетсяftp myftpbox.com < commands.txt, он подключается к FTP и выполняет список команд, помещенный в файлcommands.txt.
ПРИМЕЧАНИЕ: будьте осторожны при использовании > потому что вы можете переопределить существующий файл без какого-либо подтверждения, вы можете изменить это, запустив set -o noclobber .
Надеюсь, это поможет.
