Почему sed действует по-разному в зависимости от выходного файла?

Если я запустил:

cat messages.txt | sed -e 's/a/a/g' > messages.txt 

на один большой файл (2500+ строк) Я обнаружил, что в результате получится только около 900 строк после команды в cygwin и не будет никаких строк в gentoo. Однако, если я запускаю

 cat messages.txt | sed -e 's/a/a/g' > other_messages.txt 

он сохраняет все строки, как следует.

Мой вопрос в том, почему и есть ли способ сделать это иначе, чем

 cat messages.txt | sed -e 's/a/a/g' > other_messages.txt rm messages.txt mv other_messages.txt messages.txt 

  • Как найти и заменить текст sed, содержащий звездочку *
  • Как получить последнее вхождение строк между двумя шаблонами из файла?
  • Найти все слова, начинающиеся с Q
  • Найти и заменить строки в текстовом файле на выходе из другого файла
  • Печатать строки файла между двумя шаблонами соответствия
  • Переупорядочить несколько линейных блоков с помощью Sed
  • Каково использование шаблона перед заменой команды в sed
  • Как найти и заменить новую строку?
  • 4 Solutions collect form web for “Почему sed действует по-разному в зависимости от выходного файла?”

    Почему бы вам просто не написать

     sed -i -e 's/a/a/g' messages.txt 

    -i означает «на месте»,

    Ответ fschmitt является лучшим при использовании sed; однако в более общем смысле этот анти-шаблон:

     cat infile | filter > infile 

    вероятно, вызовет у вас множество проблем. Например, если у меня есть файл с именем infile который выглядит так:

     Hello World 

    и запустите эту команду:

     cat infile | tr "[:upper:]" "[:lower:]" 

    я получил

     hello world 

    Но если я запустил cat infile | tr "[:upper:]" "[:lower:]" > infile cat infile | tr "[:upper:]" "[:lower:]" > infile Я получу пустой файл. Зачем?

    Ну, когда вы используете оператор перенаправления вывода > вы говорите: «Поместите мой стандартный вывод в этот файл, и если этот файл существует, перепишите его». Теперь вы можете подумать, что это должно сработать, так как ваш фильтр вернет все строки исходного файла. Однако то, что часто заканчивается, заключается в том, что оболочка будет сжимать ваш файл до того, как будут прочитаны строки. Затем ваша команда фильтра перейдет к чтению строк из пустого файла, не найдет ни одного и, следовательно, не вернет ни одного. В некоторых местах вам может быть достаточно «повезло», чтобы некоторые строки были прочитаны до того, как файл обрушится, но лучше всего просто избегать этого шаблона.

    Чтобы обойти эту проблему, у вас есть несколько вариантов. Один из них заключается в том, чтобы просто сделать что-то вроде:

     cat infile | filter > tmpfile; mv tmpfile infile 

    Если вам нужно быть уверенным, что ваш временный файл не будет сжимать какой-либо другой файл или другие неприятные вещи произойдут с ним, вы должны посмотреть в mktemp . (см. man mktemp и info coreutils mktemp )

    Другой вариант – использовать sponge из moreutils .

    Кроме того, многие из этих примеров являются примерами бесполезных применений cat .

    Еще один (переносимый) способ редактирования файла на месте – использовать ed .

     # cf. http://wiki.bash-hackers.org/howto/edit-ed cat <<-'EOF' | ed -s messages.txt H ,g/a/s//b/g wq EOF # ... or read the file contents into a variable, modify it and write it back to file file_contents="$(cat messages.txt)" printf '%s' "$file_contents" | sed -e 's/a/b/g' > messages.txt # ... and, if you want to play around with a file descriptor hack, ... # (As long as there's a fd associated with a file, the file can be accessed via the fd.) exec 3<messages.txt # open file on fd 3 for reading rm -f messages.txt sed -e 's/a/b/g' <&3 > messages.txt 

    Вы можете использовать Vim в режиме Ex:

     ex -sc '%s/OLD/NEW/g|x' messages.txt 
    1. % выбрать все строки

    2. s заменить

    3. Глобальная замена

    4. x сохранить и закрыть

    Linux и Unix - лучшая ОС в мире.