Чтобы получить первые два столбца вывода:
$ cut -d, -f1 <file | sort | uniq -c | awk -vOFS=, '{ print $2, $1 }'
A,3
B,2
C,2
D,1
Это извлекает первый столбец исходного файла, сортирует его и подсчитывает количество повторяющихся записей. awk
в конце просто меняет местами столбцы и вставляет запятую в -между ними.
Последний столбец может быть с
$ sort -u <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }'
2
2
1
1
Это сортирует исходные данные и отбрасывает дубликаты. Затем извлекается первый столбец и подсчитывается количество дубликатов , что . awk
в конце извлекает только счетчики.
Комбинируя их с помощью bash
иpaste
:
$ paste -d, <( cut -d, -f1 <file | sort | uniq -c | awk -vOFS=, '{ print $2, $1 }' ) \
<( sort -u <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }' )
A,3,2
B,2,2
C,2,1
D,1,1
Если вы предварительно -отсортируете данные, это может быть немного сокращено (и значительно ускорено):
$ sort -o file file
$ paste -d, <( cut -d, -f1 <file | uniq -c | awk -vOFS=, '{ print $2, $1 }' ) \
<( uniq <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }' )
A,3,2
B,2,2
C,2,1
D,1,1
`...`
и $(...)
- это одно и то же с разным синтаксисом, один из оболочки Bourne, другой из оболочки Korn, первый устарел, но все еще поддерживается Bourne -как оболочки для обратной совместимости с древним Bourne. оболочка.
В других оболочках для этого используется другой синтаксис. Например, fish
имеет (...)
, а rc
/ es
имеет `cmd
или `{more complex cmd}
или `(sep){cmd}
, чтобы указать другое поведение разделения. ksh93
и mksh
также имеют${...; }
(вариант без подоболочки ).
В любом случае, это синтаксис языка оболочки, поэтому вам нужна оболочка для его интерпретации и выполнения подстановки команд.
В:
sudo cmd1 `cmd2`
В Борне -как снаряды, оболочка
cmd2
в дочернем процессе, вывод которого перенаправляется в канал $IFS
zsh
; некоторые варианты ksh также выполняют раскрытие фигурных скобок)sudo
, выполняемой в другом дочернем процессе. sudo
затем меняет uid и запускает команду, которая передается в качестве аргумента.
Если вы хотите, чтобы cmd2
запускался с другим uid,вам потребуется sudo
для запуска оболочки для интерпретации кода оболочки, выполняющего подстановку команд:
sudo sh -c 'cmd1 $(cmd2)'
sudo fish -c 'cmd1 (cmd2)'
sudo rc -c 'cmd1 `cmd2'
и так далее.
Обратите внимание, что в Bourne -, как и в оболочках, подстановка команд по-прежнему выполняется в двойных кавычках, поэтому не не:
sudo sh -c "cmd1 $(cmd2)"
Во-первых, это не будет запускать cmd2
как root
, но также выводcmd2
(на этот раз, не подвергнутый разделению + подстановке, поскольку он заключен в кавычки ), будет интерпретироваться как код sh
, что обычно представляет собой уязвимость внедрения команд. Например, если cmd2
выводит $(reboot)
, sh
, вызванная sudo
, будет запрошена интерпретация cmd1 $(reboot)
и перезагрузка.
Точно так же не делайтеили sudo sh -c 'cmd1 $(cmd2) '"$var"
, если вы хотите передать содержимое переменных вашей оболочки (, а не той, которая запущенаsudo sh -c 'cmd1 $(cmd2 '"$var"')'
sudo
)в cmd1
. ] или cmd2
. Вместо этого передайте содержимое этих переменных в виде дополнительных аргументов вsh
(не внутри кода аргумента )или через переменные среды (, чтобы они стали переменными оболочки. начато sudo
а также):
sudo sh -c 'cmd1 $(cmd2) "$1"' sh "$var"
sudo VAR="$var" sh -c 'cmd1 $(cmd2) "$VAR"'
sudo sh -c 'cmd1 $(cmd2 "$1")' sh "$var"
sudo VAR="$var" sh -c 'cmd1 $(cmd2 "$VAR")'
Здесь всегда можно сделать:
sudo cmd1 $(sudo cmd2) "$var"
sudo cmd1 $(sudo cmd2 "$var")
То есть пусть ваша оболочка запускает обе команды с помощью двух отдельных вызовов sudo
, чтобы обе запускались с повышенными привилегиями.
Как упоминалось выше, в Bourne -, подобно оболочкам (, но это также относится, хотя и по-другому, к csh -, подобно оболочкам ), подстановка команд без кавычек подлежит разделению + подстановке, поэтому вы оставляйте $(cmd2)
без кавычек в cmd1 $(cmd2)
, только если cmd2
выводит список разделенных $IFS
шаблонов подстановочных знаков. Если вы хотите, чтобы выводcmd2
(без завершающих символов новой строки )передавался целиком как один аргумент в cmd1
, вам нужно cmd1 "$(cmd2)"
или, что более вероятно, cmd1 -- "$(cmd2)"
чтобы убедиться, что аргумент не рассматривается как опция (при условии, что cmd1
поддерживает этот --
end -of -маркер опции ).
Таким образом, для вашего конкретного варианта использования это будет:
sudo DEVICE="$device" sh -c 'mount -- "$(blkid -u -- "$DEVICE")"'
Или звонить mount
только в случае успеха blkid
:
sudo DEVICE="$device" sh -c '
output=$(blkid -u -- "$DEVICE") &&
mount -- "$output"
'