Чи є команда Unix для додавання деяких рядкових даних до текстового файлу?
Щось на зразок:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Чи є команда Unix для додавання деяких рядкових даних до текстового файлу?
Щось на зразок:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Відповіді:
sed -i.old '1s;^;to be prepended;' inFile
-i
записує зміну місця і приймає резервну копію, якщо надано якесь розширення. (У цьому випадку .old
)1s;^;to be prepended;
замінює початок першого рядка заданим рядком заміни, використовуючи ;
як роздільник команди.\n
після передбавки; залежно від їх потреб. Охайний розчин.
inFile
включати каталоги в його шлях?
\n
. Слід спочатку прочитати коментарі. Блін.
'1s;^;my-prepended-line\;\n;'
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';
і це заплуталося в міру перетворення \t
і \n
.
echo "to be prepended"$'\n'"$(cat text.txt)"
Я здивований, що ніхто про це не згадував.
cat <(echo "before") text.txt > newfile.txt
що, мабуть, природніше, ніж прийнята відповідь (друкувати щось та передати це команді заміщення є лексикографічно протиінтуїтивно зрозумілим).
... і викрадаючи те, що сказав Райан вище, sponge
вам не потрібен тимчасовий файл:
sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt
EDIT: Схоже, це не працює в Bourne Shell /bin/sh
Використовуючи рядок тут - <<<
, ви можете:
<<< "to be prepended" < text.txt | sponge text.txt
<<(echo "to be prepended") < text.txt
та <<< "to be prepended" < text.txt
конструкції не працюють в баш; вони вимагають zsh.
Це одна з можливостей:
(echo "to be prepended"; cat text.txt) > newfile.txt
напевно, ви не зможете легко обійти проміжний файл
Альтернативи (можуть бути громіздкими з втечею оболонки):
sed -i '0,/^/s//to be prepended/' text.txt
cat <(echo "to be prepended") text.txt > newfile.txt
. Подумайте про це, я не впевнений, що моє пов’язане, тому я розміщую окрему відповідь.
Це допоможе сформувати вихід. - означає стандартний вхід, який забезпечується через трубу від луни.
echo -e "to be prepended \n another line" | cat - text.txt
Щоб перезаписати файл, потрібен тимчасовий файл, оскільки він не може передаватися назад у вхідний файл.
echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
text.txt
хоч як вимагається, але відображає його у stdout. Вихід може бути переведений в інший файл, якщо це працює для ОП
Віддавайте перевагу відповіді Адама
Ми можемо полегшити використання губки . Тепер нам не потрібно створювати тимчасовий файл і перейменовувати його за
echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
Примітка:
Це може мати несподівані побічні ефекти, зокрема потенційно замінити символьне посилання звичайним файлом, закінчившись різними дозволами на файл та змінивши дату створення (народження) файлу.
sed -i
, як у відповіді принца Джона Веслі , намагається принаймні відновити початкові дозволи, але застосовуються й інші обмеження.
Ось проста альтернатива, що використовує тимчасовий файл (це дозволяє уникнути зчитування всього вхідного файлу в пам'яті так, як це робить рішення shime ):
{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt
Використання групової команди ( { ...; ...; }
) є дещо ефективнішим, ніж використання підзаголовка ( (...; ...)
), як у рішенні 0xC0000022L .
Перевагами є:
Це легко контролювати , буде новий текст повинен бути безпосередньо передують першу лінію або він повинен бути включений в якості нового рядка (s) (просто додати \n
до printf
аргументу).
На відміну від sed
рішення, воно працює, якщо вхідний файл порожній ( 0
байти).
sed
Рішення може бути спрощена , якщо намір полягає в тому, щоб випереджати один або кілька цілих рядків в існуючий контент (припускаючи , що вхідний файл не є порожнім):
sed
i
Функція ' вставляє цілі рядки:
З GNU sed
:
# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile
Портативний варіант, який також працює з macOS / BSD sed
:
# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile
Зауважимо, що потрібний буквальний новий рядок після цього \
.
Використання поважної ed
утиліти POSIX :
Примітка:
ed
незмінно спочатку читає вхідний файл у цілому в пам'ять.Щоб додати безпосередньо до першого рядка (як і в sed
цьому, це не буде працювати, якщо вхідний файл повністю порожній ( 0
байти)):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-s
придушені ed
повідомлення про статус.ed
як багаторядковий тут-документ ( <<EOF\n...\nEOF
), тобто через stdin ; За замовчуванням розкриття рядка буде виконано в таких документах (оболонки змінної інтерполяції); котирування відкриття роздільник для придушення , що (наприклад, <<'EOF'
).1
робить 1-й рядок поточною лінієюs
виконує підстановку рядка на основі регулярних виразів у поточному рядку, як у sed
; ви можете включити буквальні нові рядки в текст підстановки, але вони повинні бути \
відмічені.w
записує результат назад в файл (обов для тестування, заміни w
з ,p
тільки роздрукувати результат, без зміни вхідного файлу).Щоб додати один або кілька цілих рядків :
Як і у випадку sed
, i
функція незмінно додає текстовий текст, який потрібно вставити.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 i
робить 0
(початок файлу) поточний рядок і починає режим вставки ( i
); зауважте, що номери рядків інакше базуються 1
..
власним рядком.Можливо, нічого вбудованого, але ви могли написати своє досить легко, як-от так:
#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"
Щось подібне хоча б ...
$$
Однак використання недостатньо для виробничого коду (атака google symlink); але це, звичайно, краще, ніж статичне ім'я файлу.
mktemp
За певних обставин, попередньо створений текст може бути доступний лише від stdin. Тоді ця комбінація спрацює.
echo "to be prepended" | cat - text.txt | tee text.txt
Якщо ви хочете опустити tee
вихід, додайте > /dev/null
.
tee
не вилазить text.txt
перед тим, cat
як прочитати її? Я думаю, що ні - що зробило б це рішення небезпечним для здоров'я файлу.
lenA=1000000; yes a | head -c $lenA > a.txt; lenB=10000; b=$(yes b | head -c $lenB); echo "$b" | cat - a.txt | tee a.txt > /dev/null
. Якщо lenA
1000000 (файл 1Mb) і lenB
10000 (10Kb текст наперед), то файл "a.txt" перезаписується 20 кб літер "b". Це повністю порушено. Тепер, якщо ви використовуєте 1Mb a.txt та 1Mb текст для підготовки, tee
переходить у цикл, що генерує файл 7Gb +, мені довелося зупинити команду. Отже, очевидно, що результат непередбачуваний для великих розмірів. У мене немає інформації, чи має це працювати на невеликих розмірах.
Рішення:
printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt
Зауважте, що це безпечно для всіх видів входів, оскільки немає розширень. Наприклад, якщо ви хочете зробити передоплату !@#$%^&*()ugly text\n\t\n
, це просто спрацює:
printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt
Остання частина, що залишилася для розгляду, - це видалення пробілів у кінці файлу під час заміни команди "$(cat file.txt)"
. Усі напрямки роботи для цього відносно складні. Якщо ви хочете зберегти нові рядки в кінці file.txt, дивіться це: https://stackoverflow.com/a/22607352/1091436
file.txt
більше, ніж може бути вписаний до списку аргументів printf
.
Інший спосіб використання sed
:
sed -i.old '1 {i to be prepended
}' inFile
Якщо попередньо попереджений рядок є багаторядковим:
sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
sed -i '1ito be prepended' inFile
- або це дозволено лише для GNU sed?
sed
, то i
команда з подальшою зворотною косою риси і нового рядка, і кожному рядку введення , за винятком останніх кінців за допомогою зворотного косою риси теж. GNU sed
дозволяє скорочувати лінії, про які ви запитуєте, але це лише GNU sed
. "
Як перевірено в Bash (в Ubuntu), якщо починати з тестового файлу через;
echo "Original Line" > test_file.txt
можна виконати;
echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt
або, якщо версія bash занадто стара для $ (), ви можете використовувати зворотні посилання;
echo "`echo "New Line"; cat test_file.txt`" > test_file.txt
і отримувати наступний вміст "test_file.txt";
New Line
Original Line
Немає файлу-посередника, просто баш / ехо.
Ще одне досить пряме рішення:
$ echo -e "string\n" $(cat file)
cat
розширення параметрів у подвійних лапках є досить вагомою причиною зниження рівня . Цей код розбиває вміст файлу на слова і передає кожне з них як окремий аргумент echo
. Ви втрачаєте оригінальні межі аргументів, ви втрачаєте нові рядки / вкладки / тощо., А рядки на зразок \t
та \n
в оригінальному тексті замінюються вкладками та новими рядками, а не зберігаються такими, якими вони були.
Я рекомендую визначити функцію, а потім імпортувати та використовувати її там, де потрібно.
prepend_to_file() {
file=$1
text=$2
if ! [[ -f $file ]] then
touch $file
fi
echo "$text" | cat - $file > $file.new
mv -f $file.new $file
}
Потім використовуйте його так:
prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"
Вміст вашого файлу буде:
This is second
This is first
Я збираюся використовувати цей підхід для впровадження оновлення журналу змін.