Как записать в первые n строк файла в bash

#bash

#bash

Вопрос:

У меня есть файл test.txt со следующим содержимым

 first
second
AAA
BBB
CCC
DDD
 

И я хочу удалить первые две строки и добавить новые значения в первые две строки,

итак,

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

 AAA
BBB
CCC
DDD
 

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

 new value at line 1
new value at line 2
AAA
BBB
CCC
DDD
 

Итак, я попробовал приведенную ниже команду, но как я могу удалить первые две строки?

 SERVER_HOSTNAME=$(hostname)
SERVER_IP=$(ip -o route get to 8.8.8.8 | sed -n 's/.*src ([0-9.] ).*/1/p')
sed -i "1s/.*/$SERVER_HOSTNAME/" /tmp/test.txt
sed -i "2s/.*/$SERVER_IP/" /tmp/test.txt
 

Моя проблема в том, что когда я сначала удаляю первые две строки и выполняю приведенную выше команду, она заменит номер строки 1 и два новыми значениями, но я хочу добавить их сверху, чтобы остальные (уже существующее содержимое сместится вниз) опустились.

Комментарии:

1. Помогает ли это? Как мне удалить первые n строк файла ascii с помощью команд оболочки?

2. @Aplet123 для удаления да, но мой код заменяет значения, а не сдвигает содержимое вниз. есть идеи по этому поводу?

3. Почему вы сначала удаляете первые две строки? Ваша sed команда уже демонстрирует, что она может заменить каждую строку.

4. Обратите внимание, что стандартная семантика файловой системы UNIX позволяет выполнять замену на месте только там, где новое содержимое имеет точно такое же количество байтов, что и старое содержимое . В любом другом случае (как при использовании sed -i ) вы не просто изменяете файл, вы полностью заменяете его новым файлом, написанным с нуля. (Единственными исключениями являются нестандартные расширения, но даже они, как правило, позволяют вставлять по одному блоку за раз на границах блоков , поэтому вы не можете просто добавить дополнительную строку в любое случайное место, которое вам нравится).

Ответ №1:

Ваш существующий sed уже делает то, что вы хотите; вам не нужно сначала удалять первые две строки самостоятельно.

 $ cat tmp.txt
first
second
AAA
BBB
CCC
DDD
$ SERVER_HOSTNAME=example.local
$ SERVER_IP=127.0.0.1
$ sed -i "1s/.*/$SERVER_HOSTNAME/;2s/.*/$SERVER_IP/" tmp.txt
$ cat tmp.txt
example.local
127.0.0.1
AAA
BBB
CCC
DDD
 

Комментарии:

1. это ничего не делает, но выдает вывод

2. Вы можете добавить -i себя; Я просто демонстрирую, что вам не нужно явно удалять первые две строки самостоятельно.

3. куда я должен добавить -i ?

4. Там же, где и сейчас. То, что у вас есть сейчас, уже работает. Вам просто нужно не редактировать файл самостоятельно перед запуском sed .

5. Вызов sed в этом ответе ничего не «исправляет»; это просто более простая версия того, что у вас уже есть.

Ответ №2:

Не запускайте sed -i повторно. Вместо этого объедините все ваши команды в один скрипт.

 sed -i "1s/.*/$(hostname)/
    2s/.*/$(ip -o route get to 8.8.8.8)/
    2s/.*src ([0-9.] ).*/1/" /tmp/test.txt
 

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

(У IIRC ip есть опции для создания машиночитаемых выходных данных; вероятно, вам следует изучить это вместо замены ненужных частей.)

Если вы хотите добавить, а затем удалить, команды sed d и a делают это соответственно. Но удаление двух и добавление двух, очевидно, эквивалентно замене двух.

 sed -i "1d
1ahello
2d
2ahello" file
 

К сожалению, a команда плохо стандартизирована, и неясно, как две s команды не будут работать, поэтому я оставляю это как набросок.

Комментарии:

1. Это не сдвигает содержимое вниз, оно заменяет строки

2. Вы можете использовать a вместо s , если хотите добавить строку; но ваш вопрос выглядит так, как будто вы хотите удалить две, а затем добавить две. Если это не то, что вы хотите, не могли бы вы уточнить?

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

4. Нет, я не вижу, чем это отличается от изменения первых двух строк за один раз. Похоже, у вас действительно есть два отдельных вопроса.

Ответ №3:

Не могли бы вы, пожалуйста, попробовать следующее, написанное и протестированное с показанными примерами в GNU awk . Это отредактирует 1-ю и 2-ю строки со значениями переменных оболочки и выполнит сохранение на месте в самом Input_file.

Если вы хотите сохранить содержимое 1-й строки, а также распечатать текущее содержимое, тогда можно удалить next FNR==2 FNR==1 условия ИЛИ.

 SERVER_HOSTNAME=$(hostname)
SERVER_IP=$(ip -o route get to 8.8.8.8 | sed -n 's/.*src ([0-9.] ).*/1/p')
awk -v server_ip="$SERVER_IP" -v server_hostname="$SERVER_HOSTNAME" '
FNR==1{ print server_hostname; next}
FNR==2{ print server_ip;     ; next}
1
' Input_file > temp amp;amp; mv temp Input_file
 

Объяснение приведенного выше решения:

 awk -v server_ip="$SERVER_IP" -v server_hostname="$SERVER_HOSTNAME" '
##Starting awk program from here, creating server_ip and server_hostname vars with respective shell vars.
FNR==1{ print server_hostname; next}
##Checking condition if this is 1st line then print server_hostname.
FNR==2{ print server_ip;     ; next}
##Checking condition if this is 2nd line then print server_ip here.
1
##1 will print current line.
' Input_file
##Mentioning Input_file name here.
 

Комментарии:

1. Вам не нужно удалять первые 2 строки, а затем вставлять 2 новые строки, вы могли бы заменить 1-ю 2 строками, в которых 2 новых значения, вот так просто.

2.каковы input_file temp

3. @JananathBanuka, это просто способ сделать inplace в не gnu awk , он сохранит вывод в temp файл, а затем переименует его в фактический Input_file, если awk команда была успешной для размещения вывода в temp файле.

4. Как добавить к этому еще одну строку? скажем, я хочу заменить первые три строки?

5. @JananathBanuka, прошу прощения, но в SO рекомендуется только 1 сообщение 1 вопрос (подсказка: создайте переменные новых строк и распечатайте их соответствующим образом в указанных условиях), просим вас, пожалуйста, поиграйте с этими решениями, и вы можете открыть новый вопрос, если хотите получить рекомендации, приветствия исчастливого обучения.

Ответ №4:

Вы можете использовать это gnu sed :

 gsed -i -e "1i\$SERVER_HOSTNAMEn$SERVER_IP" -e '1,2{d;q;}' /tmp/test.txt
 

Или с помощью POSIX sed:

 sed -i.bak "1,2{d;q;};3i\
$SERVER_HOSTNAME
3i\
$SERVER_IP
" /tmp/test.txt
 

Комментарии:

1. как записать это в одну строку?

2. Как добавить к этому еще одну строку? скажем, нам нужно обновить первые три строки?

3. Но это снова заменит существующую строку в 3-й строке и заменит ее новым значением. Можем ли мы, не заменяя 3-ю строку, сдвинуть строки вниз и добавить некоторые значения в 3-ю строку?