Ничего страшного с sed
:
sed 's/","/\n/g' file
s / search / replace / g
ищет термин поиск
и заменяет его термином replace
. g
указывает, что поиск-замена должна выполняться глобально, то есть несколько раз в строке.
Другие уже отметили ошибку в вашем коде и правильно предположили, что для ваших исходных данных-заполнителей лучше выбрать структуру данных в виде массива, а также как убедиться, что вы правильно разбиваете строку и т. д.
Теперь, когда мы знаем, что на самом деле представляет собой ваша команда, которую вы анализируете, мы можем быть немного более изобретательными с предложениями по улучшению.
Следующий сценарий берет каждую строку вывода вашей команды 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
:
lastpipe
в сценарии с помощью shopt -s lastpipe
или Чтение данных в цикл с заменой процесса:
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
определить массив с помощью (). Если вы используете двойные кавычки, то он будет восприниматься как целая строка.
$ 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
Чтобы разделить строку по символу пробела, вы можете использовать оператор 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
не передавалось никакого аргумента вместо того, чтобы передавать этот пустой аргумент и жаловался на Это.
Другой подход с использованием awk:
echo "42 /foo/bar" | awk '{n=split($2,b,"/"); print $1,b[n]}'