У меня есть файл с данными, который я сохраняю. Теперь я хотел бы распечатать свои результаты в новый файл.
Например, давайте возьмем такой пример randomlog.log
:
Link encap:Ethernet HWaddr 08:00:00:00:00:67
inet addr:10.10.10.10 Bcast:10.10.10.10 Mask:255.255.255.0
inet6 addr: fe80::casf:sdfg:23ra:dg12/64 Scope:Link
Как мне взять только данные с 12-го по 20-й символ первой строки, а затем с 4-го по 8-й символ третьей строки? Вывод будет выглядеть примерно так:
Ethernet
t6 ad
Это возможно? Я хочу установить линию и позицию from в эту позицию.
решение1
Вот sed
подход:
$ sed -nE '1s/.{11}(.{8}).*/\1/p; 3s/.{3}(.{4}).*/\1/p' file
Ethernet
t6 a
Объяснение
Подавляет -n
нормальный вывод (нормальный — печатать каждую входную строку), так что он печатает только тогда, когда ему это указано. Включает -E
расширенные регулярные выражения.
В скрипте sed
есть две команды, обе с использованием оператора подстановки ( s/original/replacement/
). Оператор 1s/.{11}(.{8}).*/\1/p
будет работать только на первой строке (именно это и 1s
делает оператор ) и будет соответствовать первым 11 символам строки (.{11}
), затем онзахватываетследующие 8 ( (.{8})
, скобки — это «группа захвата»), а затем все остальное до конца строки ( .*
). Все это заменяется тем, что было в группе захвата ( \1
; если бы была вторая группа захвата, это было бы \2
и т. д.). Наконец, p
в конце ( s/foo/bar/p
) строка печатается после того, как была сделана замена. Это приводит к выводу только целевых 8 символов.
Вторая команда имеет ту же общую идею, за исключением того, что она будет выполняться только на 3-й строке ( 3s
) и сохранит 4 символа, начиная с 4-го.
То же самое можно сделать и с помощью perl
:
$ perl -ne 'if($.==1){s/.{11}(.{8}).*/\1/}
elsif($.==3){s/.{3}(.{4}).*/\1/}
else{next}; print; ' file
Ethernet
t6 a
Объяснение
Это -ne
означает «считывание входного файла построчно и применение скрипта, заданного , -e
к каждой строке». Скрипт имеет ту же основную идею, что и раньше. Переменная $.
содержит текущий номер строки, поэтому мы проверяем, является ли номер строки или 1
, 3
и, если это так, запускаем подстановку, в противном случае пропускаем. Поэтому print
будет запущен только для этих двух строк, поскольку все остальные будут пропущены.
Конечно, это Perl, так чтоТИМТОВТДИ:
$ perl -F"" -lane '$. == 1 && print @F[11..19]; $.==3 && print @F[3..6]' file
Ethernet
t6 a
Объяснение
Здесь -a
означает «разделить каждую входную строку по символу, заданному , -F
и сохранить как массив » @F
. Поскольку заданный символ пуст, это сохранит каждый символ входной строки как элемент в @F
. Затем мы печатаем элементы 11–19 (массивы начинают отсчет с 0
) для 1-й строки и 3–7 для 3-й.
решение2
подход awk:
$ awk 'NR==1{print substr($0,12,8)};NR==3{print substr($0,4,4)}' input.txt
Ethernet
t6 a
Используется NR
для определения номера строки (в терминологии awk - записи) и соответственно печати подстроки строки. substr()
Функция имеет формат
substr(string,starting position,how much offset)
Питон
$ python -c 'import sys
> for index,line in enumerate(sys.stdin,1):
> if index == 1:
> print line[11:19]
> if index == 3:
> print line[3:7]' < input.txt
Ethernet
t6 a
Это использует <
оператор оболочки для перенаправления входного потока в процесс python из входного файла. Обратите внимание, что строки в python индексируются 0, поэтому вам нужно сместить все нужные вам номера символов на 1.
портативный путь оболочки
Это работает в ksh
, dash
, bash
. Полагается только на утилиты оболочки, ничего внешнего.
#!/bin/sh
rsubstr(){
i=0;
while [ $i -lt $2 ];
do
rmcount="${rmcount}?"
i=$(($i+1))
done;
echo "${1#$rmcount}"
}
lsubstr(){
printf "%.${2}s\n" "$1"
}
line_handler(){
case $2 in
1) lsubstr "$(rsubstr "$1" 11)" 8 ;;
3) lsubstr "$(rsubstr "$1" 3)" 5 ;;
esac
}
readlines(){
line_count=1
while IFS= read -r line;
do
line_handler "$line" "$line_count"
line_count=$(($line_count+1))
done < $1
}
readlines "$1"
И работает это так:
$ ./get_line_substrings.sh input.txt
Ethernet
t6 ad