Bash - Многомерные массивы и переменные Извлечения от вывода

Можно испытать этот мой сценарий. Это позволит Вам или указать файл, или это берет стандартный вход. Можно определить регулярное выражение Python для текста, который Вы хотите выделить. выделенные текстовые значения по умолчанию к неоновому зеленому (эй я использую черный фон!), Но можно изменить цветовой код ANSI.

#!/usr/bin/env python

import sys
import re

def highlight_text(text,pat):
    def replacement_funk(matchobj):  return '\x1b[42m%s\x1b[0m'%matchobj.group(0)
    return re.sub(pat,replacement_funk,text)

if __name__ == '__main__':
    if len(sys.argv) == 2:
        input = sys.stdin
        pat = sys.argv[1]
    elif len(sys.argv) == 3:
        input = open(sys.argv[2])
        pat = sys.argv[1]
    else:
        sys.stderr.write("colorme pattern [inputfile]")
    text = input.read()
    print highlight_text(text,pat)

Вот пример.

blessburn@blessburn:/tmp$ cat test.txt | ./colorme.py an

Перспективы организованного вывода войск НАТО из Афганистана перенесли две неудачи, поскольку президент Hamid Karzai потребовал пределов на войска Соединенных Штатов, и Талибан остановил мирные переговоры.

blessburn@blessburn:/tmp$ ./colorme.py '(Af.*? |NA[\w]{2})' test.txt

Перспективы организованного вывода войск НАТО из Афганистана перенесли две неудачи, поскольку президент Hamid Karzai потребовал пределов на войска Соединенных Штатов, и Талибан остановил мирные переговоры.

8
31.01.2014, 16:56
4 ответа

Ваша основная проблема состоит в том, что последняя команда в конвейере работает в подоболочке, как все другие команды в конвейере. Дело обстоит так в большинстве оболочек. ATT ksh и zsh являются исключениями: они выполняют последнюю команду конвейера в родительской оболочке.

Начиная с удара 4.2, можно сказать удару вести себя как ksh и zsh путем установки lastpipe опция.

#!/bin/bash
USERS=()
shopt -s lastpipe
w | awk '{if(NR > 2) print $1,$2,$3}' | while read line; do
  USERS+=("$line")
done
echo ${#USERS[@]}

С другой стороны, можно использовать замену процесса вместо канала, так, чтобы read управляйте выполнениями в основном процессе оболочки.

#!/bin/bash
USERS=()
while read line; do
  USERS+=("$line")
done < <(w | awk '{if(NR > 2) print $1,$2,$3}')
echo ${#USERS[@]}

С другой стороны, можно использовать портативный подход, который работает в оболочках, которые не имеют процесса susbtitution, ни ksh/zsh поведения, такого как Bourne, тире и pdksh. (Вам все еще нужно (фунт) ksh, удар или zsh для массивов.) Выполненный все, что требует данных из конвейера в конвейере.

#!/bin/bash
USERS=()
shopt -s lastpipe
w | awk '{if(NR > 2) print $1,$2,$3}' | {
  while read line; do
    USERS+=("$line")
  done
  echo ${#USERS[@]}
}
5
27.01.2020, 20:10

С shopt -s lastpipe можно принять последнее управление конвейером в текущую среду оболочки. Это решает Вашу проблему. Я предполагаю, что эта функция не всегда была в ударе, так избегайте его, если Вы хотите широко совместимый код.

Совместимая альтернатива:

export_array="$(w | awk '{if(NR > 2) print $1,$2,$3}' | 
  { USERS=(); while read line; do
      USERS[]="$line"
    done
    declare -p USERS; } )"
eval "$export_array"
4
27.01.2020, 20:10
  • 1
    Сделал Вы имеете в виду USERS+=("$line") вместо USERS[]="$line"? –  Runium 08.06.2013, 02:36
  • 2
    @Sukminder, Конечно, нет. Я заменил это потому что AFAIR += нотация была добавлена в последних версиях удара. Обе команды делают то же. –  Hauke Laging 08.06.2013, 02:40

Массивы Bash являются одномерными. Если Вы хотите держать заказанный отдельные значения для каждой строки, одно решение состоит в том, чтобы использовать ассоциативные массивы. Сырой пример:

Также будьте осторожны с теми прописными именами переменной, поскольку они могут столкнуться с переменными среды.

#!/bin/bash

declare -i i=0 j=0
declare -A w

while read -r user tty from _;do
    ((++i > 2)) || continue
    w["$j.user"]="$user"
    w["$j.tty"]="$tty"
    w["$j.from"]="$from"
    ((++j))
done < <(w)

for ((i = 0; i < j; ++i)); do
    printf "entry %-2d {\n  %-5s: %s\n  %-5s: %s\n  %-5s: %s\n}\n" \
    "$i" \
    "user" "${w[$i.user]}" \
    "tty"  "${w[$i.tty]}" \
    "from" "${w[$i.from]}"
done
4
27.01.2020, 20:10

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

    readarray -s2 -t my_w_array < <(w | awk '{ print $1":"$2":"$3 }')

можно затем разделить его при печати его, как:

    printf '%s\n' "${my_w_array[@]//:/ }"
3
27.01.2020, 20:10

Теги

Похожие вопросы