Чи існує інший простий спосіб додати рядок до кінця файлу, крім ">>"?


21

Останнім часом я повторюю короткі пропозиції до tree_holeфайлу.

Я використовував echo 'something' >> tree_holeцю роботу.

Але мене завжди хвилювало, що робити, якщо >замість цього я помиляюся >>, оскільки це роблю часто.

Тому я зробив свій власний функціональний баш в bashrc:

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

Але мені цікаво, чи є ще один простий спосіб додати рядки до кінця файлу. Тому що мені може знадобитися це часто використовувати в інших випадках.

Чи є?


9
Ви не забудете, що використовуєте обхід кожного разу, коли входите>? Одного разу у мене з'явився псевдонім rm="rm -i"і в іншому середовищі написав rm *очікування питань підтвердження. Ви вивчаєте небезпечні звички!
Вальтер А

9
@WalterAе, його "вирішення" не дозволяє йому вводити> замість >>, він просто виконує "th__dis_sentence", який нічого не робить, якщо псевдонім не визначений.
Випадково832

1
@ Ranom832 правильний для його роботи. Попередження є для "рішення", як ноклоббер. Коли він використовує щось на кшталт noclobber у своїй звичайній оболонці, він може використовуватись> коли він тимчасовий корінь і хоче щось додати.
Вальтер А

7
@ Random832 & WalterA Зазвичай я нічого не кажу про це, коли бачу, але я подумав, що, можливо, друге повідомлення раз у той час може бути корисним. Профіль користувача Дзен не має багато деталей, тому я не впевнений, чи справді ви знаєте, що його "вирішення" є правильною формою. Можливо, ви повинні сказати їхнє "вирішення" чи "реферат" ОП . Можливо, ви знаєте Дзен особисто, і тому знаєте, що його правильно, і в цьому випадку прошу пробачення. Не велика справа, я лише згадую це, бо знаю, що не дуже оцінив би це, якби ти використовував цю форму, щоб говорити про мене.
Селада

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$ 

3
Це остаточна відповідь. Зауважте, що ви можете перезаписати файл, якщо змусити його >|. zshуможливлює цю поведінку за замовчуванням.
orion

1
@orion Як ввімкнути / вимкнути це в zsh? Я не пригадую, щоб явно його відключати, але перезапис працює чудово на моєму zsh.
муру

2
Це setopt noclobberі setopt clobber. Здається, це не зовсім "за замовчуванням", це залежить від конфігураційних файлів, які постачаються разом із вашим дистрибутивом.
orion

@muru повинен працювати з set [+-]Cбудь-якою сучасною оболонкою
mikeserv

3
@Zen set +o noclobberin bash, або 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) Як правило, слід розмістити подвійні лапки навколо розширень параметрів (те, що починається з а $), щоб запобігти глобалізації, розбиттю слів і пов'язаним з цим пробілам. Інтернет- додаток ShellCheck може вирішити цю та інші проблеми в скриптах bash. На відповідну записку "$@"це набагато безпечніше , ніж $*.
PM 2Ring

3
2) Як правило, викличте readкоманду з -rможливістю запобігання тому, щоб будь-які зворотні косої риски на вході не переходили до наступного символу. 3) У скриптах bash звичайно використовувати малі регістри імен змінних скриптів, оскільки ВСІ ВНУТРІШНІ КАРТИ використовуються для системних змінних. Отже, якщо ви використовуєте верхній регістр для власних змінних, ви заплутаєте людей, які читають ваш код, і ви можете випадково перекрити системну змінну, яку ви хочете використовувати пізніше в сценарії. І якщо ви будете джерелом сценарію, він буде клобувати змінні для наступних команд.
PM 2, 15

3
4) echoзручна для друку фіксованих рядків, але може робити несподівані речі з довільними даними, особливо в системах GNU. Це набагато безпечніше використання printf. Дивіться unix.stackexchange.com/questions/65803/… для отримання додаткової інформації, особливо відповідь Стефана Шазеласа.
PM 2,

3
@PM 2Ring, Сьогодні я дізнався багато речей від вас, велике спасибі .. Я виправлю їх якнайшвидше.
Sepahrad Salour

1
Приємної роботи, Сепаграде!
14:00 15

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щоб придушити кількість байтів.


3
Хороша ідея ™ перевірити свій код, перш ніж публікувати його як відповідь ...
PM 2Ring

1
Рекомендувати dd- це погана ідея. ddне надійно записує свої дані на свій вихід , не тоді, коли один з них не є звичайним файлом чи блоковим пристроєм
Жил "SO- перестань бути злим"

@ gilles, ви неправильно представляєте інформацію за цим посиланням, коли кількість не вказана, dd скопіює всі наявні дані, як це робить кішка.
Ясен

-1

Я хотів би використовувати sed(навіть із резервною копією - див. Розширення після -i):

sed -i.bak '$ a\something' /Users/zen1/zen/pythonstudy/tree_hole

Чому я не здивований ... ти маніяк сед, Костасе. :) (Це комплімент, BTW)
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напередодні дії додавання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.