Как встроить команду оболочки в sed выражение?

Я думаю, что Вы просто описали AUTO_CD.

16
16.09.2012, 23:31
5 ответов

Стандарт sed не может назвать оболочку (GNU sed имеет расширение, чтобы сделать это, если Вы только заботитесь о невстроенном Linux), таким образом, необходимо будет сделать часть обработки снаружи sed. Существует несколько решений; все требуют тщательного заключения в кавычки.

Не ясно точно, как Вы хотите, чтобы значения были расширены. Например, если строка

foo hello; echo $(true)  3

каким из следующего должен быть вывод?

k=<foo> value=<hello; echo   3>
k=<foo> value=<hello; echo   3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<foo hello
  3>

Я буду обсуждать несколько возможностей ниже.

чистая оболочка

Можно заставить оболочку читать вход линию за линией и обрабатывать его. Это - простое решение и также самое быстрое для коротких файлов. Это - самая близкая вещь к Вашему требованию “echo \2”:

while read -r keyword value; do
  echo "k=<$keyword> v=<$(eval echo "$value")>"
done

read -r keyword value наборы $keyword к первому разграниченному пробелом слову строки, и $value к остальной части строки минус запаздывающий пробел.

Если Вы хотите развернуть ссылки на переменную, но не выполнить команды вне замен команды, поместить $value в здесь документе. Я подозреваю, что это - то, что Вы действительно искали.

while read -r keyword value; do
  echo "k=<$keyword> v=<$(cat <<EOF
$value
EOF
)>"
done

sed передается по каналу в оболочку

Можно преобразовать вход в сценарий оболочки и оценить это. Sed до задачи, хотя дело не в этом легкий. Движение с “echo \2” требование (отмечают, что мы должны выйти из одинарных кавычек в ключевом слове):

sed  -e 's/^ *//' -e 'h' \
     -e 's/[^ ]*  *//' -e 'x' \
     -e 's/ .*//' -e "s/'/'\\\\''/g" -e "s/^/echo 'k=</" \
     -e 'G' -e "s/\n/>' v=\\</" -e 's/$/\\>/' | sh

Идя с сюда документом, мы все еще должны выйти из ключевого слова (но по-другому).

{
  echo 'cat <<EOF'
  sed -e 's/^ */k=</' -e 'h' \
      -e 's/[^ ]*  *//' -e 'x' -e 's/ .*//' -e 's/[\$`]/\\&/g' \
      -e 'G' -e "s/\n/> v=</" -e 's/$/>/'
  echo 'EOF'
 } | sh

Это - самый быстрый метод, если у Вас есть много данных: это не запускает отдельный процесс для каждой строки.

awk

Те же методы мы использовали с работой sed с awk. Получающаяся программа значительно более читаема. Движение с “echo \2”:

awk '
  1 {
      kw = $1;
      sub(/^ *[^ ]+ +/, "");
      gsub(/\047/, "\047\\\047\047", $1);
      print "echo \047k=<" kw ">\047 v=\\<" $0 "\\>";
  }' | sh

Используя здесь документ:

awk '
  NR==1 { print "cat <<EOF" }
  1 {
      kw = $1;
      sub(/^ *[^ ]+ +/, "");
      gsub(/\\\$`/, "\\&", $1);
      print "k=<" kw "> v=<" $0 ">";
  }
  END { print "EOF" }
' | sh
18
27.01.2020, 19:48
  • 1
    большой ответ. я собираюсь использовать чистое решение для оболочки, поскольку входной файл является действительно маленьким, и производительность не является беспокойством, также это чисто и читаемо. –  Ernest A C 17.09.2012, 13:53
  • 2
    определенный взлом, но достаточно аккуратный. например, используйте sed для обращений к xxd для декодирования длинной шестнадцатеричной строки... кошка FtH.ch13 | sed-r's / (. *text.*: [) ([0-9a-fA-F] *)]/\1$ (повторяют \2|xxd-r-p)]/; s/^ (.*) $ / отзываются эхом "\1"/g' |bash> FtHtext.ch13, Где FtH.ch13 имеет строки как "шестнадцатеричный текстовый тест панели нечто: [666f6f0a62617200]" –  gaoithe 12.01.2016, 14:38

Вы могли попробовать этот подход:

input='
keyword value value
keyword "value  value"
keyword `uname`
'

process() {
  k=$1; shift; v="$*"
  printf '%s\n' "k=<$k> v=<$v>"
}

eval "$(printf '%s\n' "$input" | sed -n 's/./process &/p')"

(если я разбираюсь в Вашем намерении). Это - вставка "процесс" в начале каждой непустой строки для создания этого сценарием как:

process keyword value value
process keyword "value  value"
process keyword `uname`

быть оцененным (eval) где процесс является функцией, которая печатает ожидаемое сообщение.

4
27.01.2020, 19:48

Если non-sed решение будет приемлемо, то этот отрывок Perl сделает задание:

$ echo "$input" | perl -ne 'chomp; /^\s*(.+?)\s+(.+)$/ && do { $v=`echo "$2"`; chomp($v); print "k=<$1> v=<$v>\n"}'
1
27.01.2020, 19:48
  • 1
    благодарит, но я избегал бы использования другого языка сценариев, если я могу, и сохранять его к стандартным командам Unix и оболочке Bourne –  Ernest A C 16.09.2012, 18:26

Имея GNU sed, вы можете использовать следующую команду:

sed -nr 's/([^ ]+) (.*)/echo "\1" \2\n/ep' input

Которая выводит:

keyword value value
keyword value  value
keyword Linux

с вашими входными данными.

Объяснение:

Команда sed подавляет регулярный вывод с помощью опции -n. -r передается для использования расширенных регулярных выражений, что избавляет нас от экранирования специальных символов в шаблоне, но это не обязательно.

Команда s используется для передачи строки ввода в команду:

echo "\1" \2

Ключевое слово get's цитирует значение not. Я передаю опцию e - которая специфична для GNU - команде s, которая говорит sed выполнить результат подстановки как команду оболочки и прочитать результаты в буфер шаблона (даже несколько строк). Использование опции p после(!) e заставляет sed печатать буфер шаблонов после выполнения команды.

14
27.01.2020, 19:48

SOLO BESO CORTO SED PURO

Haré esto

echo "ls_me" | sed -e "s/\(ls\)_me/\1/e" -e "s/to be/continued/g;"

y funcionando.

1
27.01.2020, 19:48

Теги

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