Расщепленная строка с помощью пространственного символа (странная проблема с базовым имеем)

Ничего страшного с sed :

sed 's/","/\n/g' file

s / search / replace / g ищет термин поиск и заменяет его термином replace . g указывает, что поиск-замена должна выполняться глобально, то есть несколько раз в строке.

4
06.08.2018, 12:40
4 ответа

Другие уже отметили ошибку в вашем коде и правильно предположили, что для ваших исходных данных-заполнителей лучше выбрать структуру данных в виде массива, а также как убедиться, что вы правильно разбиваете строку и т. д.

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

Следующий сценарий берет каждую строку вывода вашей команды psи читает ее как два бита, разделенных пробелом -.Тело цикла выводит прочитанные биты разными способами:

#!/bin/bash

ps -r -e -o pcpu=,comm= |
while IFS=' ' read -r pcpu comm; do
    printf 'pcpu=%s,\tcomm=%s,\tbasename of comm=%s\n' \
        "$pcpu" "$comm" "${comm##*/}"
done

Здесь commбудет содержать все после первой последовательности пробелов в выводеps(начальные пробелы перед первым столбцом будут обрезаны ).

Очевидно, вы можете вставить свой head -n 1как часть первоначального конвейера, если хотите.

Обратите внимание, что в некоторых оболочках, включая bash, цикл выполняется в подоболочке, поэтому любые созданные там переменные будут недоступны после завершения конвейера. Вbash:

этому есть два решения.
  1. Включите параметр оболочки lastpipeв сценарии с помощью shopt -s lastpipeили
  2. .
  3. Чтение данных в цикл с заменой процесса:

    while IFS=' ' read...
       #...
    done < <( ps... )
    

Пример запуска:

$ bash script.sh
pcpu=0.0,       comm=tmux,      basename of comm=tmux
pcpu=0.0,       comm=sh,        basename of comm=sh
pcpu=0.0,       comm=sh,        basename of comm=sh
pcpu=0.0,       comm=bash,      basename of comm=bash
pcpu=0.0,       comm=bash,      basename of comm=bash
pcpu=0.0,       comm=bash,      basename of comm=bash
pcpu=0.0,       comm=ps,        basename of comm=ps
pcpu=0.0,       comm=sh,        basename of comm=sh
5
27.01.2020, 20:46

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

Подробнее о массиве

$ cat test.sh
#!/bin/bash

A=(42 /foo/bar)
B=${A[0]}
C=${A[1]}
printf '%3s  %s\n' $B $(basename $C)

$ bash test.sh
 42  bar
3
27.01.2020, 20:46

Чтобы разделить строку по символу пробела, вы можете использовать оператор split+glob. Это вызывается при подстановке команды или расширении параметра, но, очевидно, не при сохранении в скалярную переменную, которая может хранить не более одного значения.

 var=$(...)

Присвоение скалярной переменной. Таким образом, весь вывод будет назначен на $var, так же, как ${var[0]}. Для назначения переменной массива это:

 var=($(...))

Теперь, прежде чем вызывать его, как всегда, его нужно настроить.:

 set -o noglob # disable the glob part which you don't want here
 IFS=' ' # split on space only
 var=($(some command)) # invoke it

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

Тогда вы не хотите вызывать его в расширении $B, $Cили $(basename...), поэтому вам нужно процитировать эти:

 printf '%3s  %s\n' "$B" "$(basename -- "$C")"

Также не забудьте поставить --для обозначения конца опций.

Поскольку вы забыли, что кавычки вокруг$C($Cбыли пустыми в вашем случае, поскольку ${A[1]}никогда не присваивалось никакого значения ), basenameне передавалось никакого аргумента вместо того, чтобы передавать этот пустой аргумент и жаловался на Это.

6
27.01.2020, 20:46

Другой подход с использованием awk:

 echo "42 /foo/bar" | awk '{n=split($2,b,"/"); print $1,b[n]}'
0
27.01.2020, 20:46

Теги

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