Есть ли другой простой способ добавить строку в конец файла, кроме `>>`?

21

Недавно я повторяю короткие предложения в tree_holeфайл.

Я использовал, echo 'something' >> tree_holeчтобы сделать эту работу.

Но я всегда беспокоился о том, что если я неправильно введу >вместо >>, так как я делал это часто.

Поэтому я создал собственный глобальный функционал bash в bashrc:

function th { echo "$1" >> /Users/zen1/zen/pythonstudy/tree_hole; }
export -f th

Но мне интересно, есть ли еще один простой способ добавить строки в конец файла. Потому что мне может понадобиться использовать это часто в других случаях.

Есть ли?

Zen
источник
9
Не забудете ли вы, что используете обходной прием каждый раз, когда вводите>? Однажды у меня был псевдоним rm="rm -i"и в другой среде написали в rm *ожидании подтверждения вопросов. Вы учитесь опасным привычкам!
Вальтер А
9
@WalterA er, его «обходной путь» не позволяет ему печатать> вместо >>, он просто запускает «th some_sentence», который ничего не делает, если псевдоним не определен.
Random832
1
@ Ranom832 подходит для его обхода. Предупреждение для «решения», такого как noclobber. Когда он использует что-то вроде noclobber в своей обычной оболочке, он может использовать> когда он временный root и хочет что-то добавить.
Вальтер А
7
@ Random832 & WalterA Обычно я ничего об этом не говорю, когда вижу, но я подумал, что иногда может быть полезно дружеское замечание. В профиле пользователя Zen не так много деталей, поэтому я не уверен, действительно ли вы знаете, что его «обходной путь» - правильная форма. Может быть, вы должны сказать их «обходной путь» или «обходной путь» ОП . Возможно, вы знакомы с дзен лично и поэтому знаете, что он прав, и в этом случае прошу прощения за шум. Ничего страшного, я просто упоминаю об этом, потому что знаю, что не очень оценил бы это, если бы вы использовали эту форму, чтобы говорить обо мне.
Селада
1
@Zen, Вы писали, что беспокоитесь о неправильном вводе> вместо >>. План Celada устранит риски в вашей среде и является хорошим решением для вас. Когда вы помогаете своему соседу (у которого нет noclobber или использует ksh) и вы потеряли свое внимание на один или два> символа, вы можете случайно перезаписать один из его файлов. Поэтому каждый раз, когда вы получаете предупреждение о ноблобере в вашем собственном окружении, слава Богу или Селаде, говорите себе: «О, будьте осторожны, пожалуйста!», Покачайте головой и подождите две секунды.
Уолтер

Ответы:

47

Установите параметр оболочки noclobber:

bash-3.2$ set -o noclobber
bash-3.2$ echo hello >foo
bash-3.2$ echo hello >foo
bash: foo: cannot overwrite existing file
bash-3.2$ 
Celada
источник
3
Это окончательный ответ. Обратите внимание, что вы все равно можете перезаписать файл, если принудительно нажать его >|. zshвключает это поведение по умолчанию.
Орион
1
@orion Как включить / отключить его в zsh? Я не помню явно отключить его, но перезапись работает на моем Zsh.
Муру
2
Это setopt noclobberи setopt clobber. Похоже, это не совсем «по умолчанию», это зависит от файлов конфигурации, которые поставляются с вашим дистрибутивом.
Орион
@muru должен работать set [+-]Cдля любой современной оболочки
mikeserv
3
@ Дзен set +o noclobberв Баш или set +C.
Руслан
7

Если вы обеспокоены тем, что ваш файл будет поврежден >оператором, вы можете изменить атрибут файла только для добавления:
в ext2 / ext3 / ext4 файловой системе : chattr +a file.txt
В файловой системе XFS :echo chattr +a | xfs_io file.txt

И если вы хотите функцию, я уже сделал функцию для себя (я использовал ее в служебном файле для регистрации результатов), вы можете изменить ее для своей цели:

# This function redirect logs to file or terminal or both!
#@ USAGE: log option data
# To the file     -f file
# To the terminal -t
function log(){
        read -r data       # Read data from pipe line

        [[ -z ${indata} ]] && return 1    # Return 1 if data is null

        # Log to /var/log/messages
        logger -i -t SOFTWARE ${data}

        # While loop for traveling on the arguments
        while [[ ! -z "$*" ]]; do
                case "$1" in
                        -t)
                                # Writting data to the terminal
                                printf "%s\n" "${data}"
                                ;;
                        -f) 
                                # Writting (appending) data to given log file address
                                fileadd=$2
                                printf "%s %s\n" "[$(date +"%D %T")] ${data}" >> ${fileadd}
                                ;;
                        *)
                                ;;
                esac
                shift           # Shifting arguments
        done
}
Сепарад Салур
источник
2
Есть несколько проблем с этим скриптом. 1) Как правило, вы должны помещать двойные кавычки вокруг раскрытия параметров (вещи, начинающиеся с a $), чтобы предотвратить сбои, разбиение слов и связанные с ними проблемы с пробелами. Онлайн- приложение ShellCheck может решить эту и другие проблемы в скриптах bash. На соответствующую записку "$@"это гораздо безопаснее , чем $*.
PM 2Ring
3
2) Обычно вы должны вызывать readкоманду с -rопцией, чтобы предотвратить обратную косую черту во входных данных от следующего символа. 3) В сценариях bash обычно используют строчные буквы для имен переменных сценария, поскольку ALL UPPER CASE используется для системных переменных. Поэтому, если вы используете верхний регистр для своих собственных переменных, вы будете путать людей, которые читают ваш код, и вы можете случайно забить системную переменную, которую вы хотите использовать позже в сценарии. И если вы создадите сценарий, он преобразует переменные для последующих команд.
PM 2Ring
3
4) echoудобен для печати фиксированных строк, но может делать неожиданные вещи с произвольными данными, особенно в системах GNU. Это гораздо безопаснее в использовании printf. См. Unix.stackexchange.com/questions/65803/… для получения дополнительной информации, особенно ответа Стефана Шазеласа.
PM 2Ring
3
@PM 2Ring, сегодня я многому у тебя научился, большое спасибо .. я исправлю их как можно скорее.
Сепарад Салур
1
Отличная работа, Сепарад!
PM 2Ring
3

Используйте teeс опцией добавления:

foo | tee -a some-file
# or
tee -a some-file <<EOF
blah blah
EOF
# or 
tee -a some-file <<<"blah blah"
Мур
источник
5
Хорошая идея, +1, но я представляю, что если ОП беспокоится о том, чтобы забыть >персонажа, то они могут беспокоиться о том, чтобы забыть о -aопции!
Селада
@Celada Полагаю, что так (но я предполагаю, что опечатка из-за пропуска одного нажатия клавиши в наборе повторяющихся нажатий с большей вероятностью произойдет, чем потеря опции).
Муру
0

многие программы, которые могут открывать файлы для перезаписи, могут альтернативно открывать их для добавления, например, gnu dd.

dd conv=notrunc oflag=append of=file

он может читать stdin или файл с именем в if= параметре add 2>/dev/nullдля подавления подсчета байтов.

Jasen
источник
3
Это хорошая идея ™, чтобы проверить свой код, прежде чем публиковать его как ответ ...
PM 2Ring
1
Рекомендовать ddэто плохая идея. ddне надежно записывает свои входные данные в свои выходные , даже если один из них не является обычным файловым или блочным устройством
Жиль "ТАК - перестать быть злым"
@gilles, вы неверно представляете информацию по этой ссылке, если счет не указан, dd скопирует все доступные данные, так же как и cat.
Ясен
-1

Я хотел бы использовать sed(даже с резервной копией - смотрите расширение после -i):

sed -i.bak '$ a\something' /Users/zen1/zen/pythonstudy/tree_hole
Костас
источник
Почему я не удивлен ... ты - маньяк, Костас. :) (Это комплимент, кстати)
PM 2Ring
@ PM2Ring Да, я очень опасен! : P
Костас
Конечно, работает способ сделать копию файла, добавить новый текст в конец, затем удалить исходный файл и переименовать копию в исходное имя. Это (1) не работает, если у вас нет прав на запись в каталог, (2) разрывает ссылки и (3) является дорогостоящим, если файл большой. Забавно, что ты поднял слово «опасный»!
G-Man говорит: «Восстанови Монику»
-1

Вы всегда можете искать через файл другими способами ...

seq 10000000 >f
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
wc -l f; tail f

... эта странно выглядящая последовательность печатает:

10000000
10000001
10000002
10000003
10000004
10000005 f
9999996
9999997
9999998
9999999
10000000
new line!
new line!
new line!
new line!
new line!

Но это глупо.

Более полезный пример может выглядеть так:

 apnd() if    shift
        then  wc -l  >&2
              printf "$@"
        fi    <>"$1" >&0

Вы можете назвать это как:

 apnd /path/to/file          \
      "${printf_fmt_string}" \
       arbitrary list of strings

И вы получите число fileстрок, записанных stderrнепосредственно перед началом действия добавления.

mikeserv
источник