Я знаю основы этих трех. И причина, по которой 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
.
Надеюсь, это поможет.