Добавить строку префикса в начало каждой строки


335

У меня есть файл, как показано ниже:

line1
line2
line3

И я хочу получить:

prefixline1
prefixline2
prefixline3

Я мог бы написать скрипт на Ruby, но лучше, если мне это не нужно.

prefixбудет содержать /. Это путь, /opt/workdir/например.

Ответы:


528
# If you want to edit the file in-place
sed -i -e 's/^/prefix/' file

# If you want to create a new file
sed -e 's/^/prefix/' file > file.new

Если prefixсодержит /, вы можете использовать любой другой символ, не входящий в prefix, или экранировать /, поэтому sedкоманда становится

's#^#/opt/workdir#'
# or
's/^/\/opt\/workdir/'

1
@benjamin, я уже проголосовал за твой ответ, однако, я предпочитаю sedдля легких задач, таких как эта. Если известен «префикс», очень легко выбрать символ, а не из «префикса».
Алок Сингхал

1
Не забывайте, что вы также можете использовать sedв конвейере, например foo | sed -e 's/^/x /' | bar.
зигг

1
@ DataMat круто. Другой способ был бы sed -e '2,$s/^/prefix/'.
Алок Сингхал

1
@BinChen экранировать /подобное \/(в строках в одинарных кавычках) или \\/(в строках в двойных кавычках)

8
Используйте, sed -e 's/$/postfix/' fileесли вы хотите добавить строку в конец каждой строки.
Брайан

122
awk '$0="prefix"$0' file > new_file

С Perl (на месте замены):

perl -pi 's/^/prefix/' file

8
С каналом / потоком или переменной:prtinf "$VARIABLE\n" | awk '$0="prefix"$0'
ThorSummoner

2
С большим файлом (12 G), awkотчеты awk: out of memory in readrec 1 source line number 1, но решение с sedуспешно завершено.
17

33

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

ex -sc '%s/^/prefix/|x' file
  1. % выбрать все строки

  2. s замещать

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


1
Для меня я просто открываю файл в vim и набираю :%s/^/prefix/, так как эта стратегия оказывается полезной во многих ситуациях
Фрэнк Брайс

23

Если ваш префикс немного сложен, просто поместите его в переменную:

prefix=path/to/file/

Затем вы передаете эту переменную и позволяете awk справиться с ней:

awk -v prefix="$prefix" '{print prefix $0}' input_file.txt


6

Использование оболочки:

#!/bin/bash
prefix="something"
file="file"
while read -r line
do
 echo "${prefix}$line"
done <$file > newfile
mv newfile $file

5

Вот хорошо читаемое решение oneliner с использованием tsкоманды moreutils

$ cat file | ts prefix | tr -d ' '

И как это происходит шаг за шагом:

# Step 0. create the file

$ cat file
line1
line2
line3
# Step 1. add prefix to the beginning of each line

$ cat file | ts prefix
prefix line1
prefix line2
prefix line3
# Step 2. remove spaces in the middle

$ cat file | ts prefix | tr -d ' '
prefixline1
prefixline2
prefixline3

'ts' не устанавливается по умолчанию во многих дистрибутивах Linux. Кроме того, отрицательное голосование, потому что завершающий «tr -d» в этом ответе удалит все пробелы из строк, а не только тот, который был добавлен «ts»
Тим Берд

3

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

К сожалению, sed, cut и т. Д. Добавили слишком много буферов и не позволили мне увидеть самые последние строки. Предложение Стивена Пенни использовать -sопцию nlбыло интригующим, и тестирование показало, что оно не вводило нежелательную буферизацию, которая меня беспокоила.

Однако было несколько проблем с использованием nl, связанных с желанием удалить ненужные номера строк (даже если вас не заботит их эстетика, могут быть случаи, когда использование дополнительных столбцов будет нежелательным). Во-первых, использование «вырезать» для удаления чисел вновь вводит проблему буферизации, так что это разрушает решение. Во-вторых, использование «-w1» не помогает, так как это НЕ ограничивает номер строки одним столбцом - оно становится шире, так как требуется больше цифр.

Это не красиво, если вы хотите захватить это в другом месте, но так как это именно то, что мне не нужно было делать (все было уже записано в файлы журналов, я просто хотел посмотреть несколько одновременно в режиме реального времени), лучший Чтобы потерять номера строк и иметь только мой префикс, нужно было начинать -sстроку с возврата каретки (CR или ^ M или Ctrl-M). Так, например:

#!/bin/ksh

# Monitor the widget, framas, and dweezil
# log files until the operator hits <enter>
# to end monitoring.

PGRP=$$

for LOGFILE in widget framas dweezil
do
(
    tail -f $LOGFILE 2>&1 |
    nl -s"^M${LOGFILE}>  "
) &
sleep 1
done

read KILLEM

kill -- -${PGRP}

1
используйте -uопцию sed, чтобы избежать буферизации.
Брайан Ларсен

2
Буферизацию можно отключить с помощью unbuffer / stdbuf, см. Unix.stackexchange.com/q/25372/6205
myroslav

2

Используя ed:

ed infile <<'EOE'
,s/^/prefix/
wq
EOE

Это заменяет для каждой строки ( ,) начало строки ( ^) на prefix. wqсохраняет и выходит.

Если строка замены содержит косую черту, sвместо этого мы можем использовать другой разделитель :

ed infile <<'EOE'
,s#^#/opt/workdir/#
wq
EOE

Я процитировал разделитель here-doc EOE(«конец ed»), чтобы предотвратить расширение параметра. В этом примере он также будет работать без кавычек, но это хорошая практика, чтобы предотвратить неожиданности, если у вас когда-либо есть $в вашем сценарии ed.


2

Используя & (всю часть ввода, которая была сопоставлена ​​с шаблоном ”):

cat in.txt | sed -e "s/.*/prefix&/" > out.txt

ИЛИ используя обратные ссылки:

cat in.txt | sed -e "s/\(.*\)/prefix\1/" > out.txt

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

    sed -i.bak 's/\(.*\)/prefix\1/' foo.txt
    
  2. Вы также можете использовать с awk, как это

    awk '{print "prefix"$0}' foo.txt > tmp && mv tmp foo.txt
    

1

Вот завернутый пример, использующий sedподход из этого ответа :

$ cat /path/to/some/file | prefix_lines "WOW: "

WOW: some text
WOW: another line
WOW: more text

prefix_lines

function show_help()
{
  IT=$(CAT <<EOF
    Usage: PREFIX {FILE}

    e.g.

    cat /path/to/file | prefix_lines "WOW: "

      WOW: some text
      WOW: another line
      WOW: more text
  )
  echo "$IT"
  exit
}

# Require a prefix
if [ -z "$1" ]
then
  show_help
fi

# Check if input is from stdin or a file
FILE=$2
if [ -z "$2" ]
then
  # If no stdin exists
  if [ -t 0 ]; then
    show_help
  fi
  FILE=/dev/stdin
fi

# Now prefix the output
PREFIX=$1
sed -e "s/^/$PREFIX/" $FILE

2
Это не будет работать, если PREFIXсодержит какие-либо специальные символы, такие как слеш.
17

Хорошая мысль ... Если вы обнаружите, что используете слэш, вы можете использовать другой разделитель с частью sed, как подробно описано здесь , что позволит вам использовать его в поиске. Другие специальные символы могут быть вставлены с помощью косой черты, напримерprefix_lines \*
Брэд Паркс

0

Для людей в системах BSD / OSX есть утилита, называемая lamламинатом. lam -s prefix fileбудет делать то, что вы хотите. Я использую это в конвейерах, например:

find -type f -exec lam -s "{}: " "{}" \; | fzf

... который найдет все файлы, exec lam для каждого из них, давая каждому файлу префикс своего имени файла. (И накачайте вывод в fzf для поиска.)


Вы правы, похоже, это только команда BSD. POSIX заменил его на вставку, но в вставке нет функции добавления полной разделительной строки. Я обновлю свой ответ.
Луч
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.