У меня есть файл с 50 символами в каждой строке и 50 строками. Каждая строка файла содержит произвольные буквы. Я хочу указать порядковый номер символа (например: 52) и распечатать соответствующую строку букв с напечатанным *
перед заданным символом.
решение1
Если жестко закодировать ваши спецификации, одним из способов будет вычисление номеров строк и столбцов из смещения (игнорируя переводы строк) и использование этих значений для выбора нужной строки и выделения нужного столбца.
С входным файлом in
, содержащим 50 строк, например:
00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
01ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
02ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
03ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
04ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
Тогда следующий скрипт должен сделать примерно то, что вы просили:
while read -p '> ' n; do
n=$((n - 1))
line=$((n / 50 + 1))
col=$((n % 50))
<in sed -n -e "${line}p" | sed "s/^.\{${col}\}/&*/g"
done
Пример взаимодействия:
> 1
*00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
> 2
0*0ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
> 49
00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst*uv
> 50
00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu*v
> 52
0*1ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
> 125
02ABCDEFGHIJKLMNOPQRSTUV*WXYZabcdefghijklmnopqrstuv
Первый вызов sed выбирает нужную строку, второй вставляет a *
в нужный столбец.
решение2
linemod50(){
dd bs=51 skip="$(($1/50))" count=1 | {
dd bs=1 count="$(($1%50-!!($1%50)))"
IFS= read -r rem
printf "*%s\n" "$rem"
} 2 >/dev/null
}
i= forty9=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW
while [ "$((i+=1))" -le 50 ]
do echo "$((i%10))$forty9"
done >file
linemod50 478 <file
1+0 records in
1+0 records out
51 bytes (51 B) copied, 9.5153e-05 s, 536 kB/s
0abcdefghijklmnopqrstuvwxyz*ABCDEFGHIJKLMNOPQRSTUVW
Это, вероятно, самое эффективное решение dd
, поскольку оно просто будет искать напрямую по вашему смещению. Однако оно не работает с широкими символами и может давать неожиданные результаты с конвейерным вводом.
Это превосходное решение с возможностью поиска ввода в локали C.
решение3
Использование GNU или FreeBSD sed
(для -r
расширенного варианта регулярного выражения):
Этот скрипт возвращается к началу как строк, так и позиций символов. Если вы не хотите, чтобы он это делал, закомментируйте или удалите строку while
.
#! /bin/bash
for O in "$@" ; do
while [[ "$O" -gt 50 ]] ; do O=$(( $O -50 )) ; done
O1=$(( $O - 1 ))
sed -r -n "$O s/^(.{$O1})(.*)/\1\*\2/ p" input.txt
done
$ for i in {1..50} ; do printf "%02i%s\n" "$i" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv" ; done > input.txt
$ ./offset.sh 3 10 52 100
03*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
10ABCDEFG*HIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
0*2ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
50ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu*v