Для этого можно использовать массивы bash, например:
arr="(first second third)"
echo ${arr[1]}
-121--38932-
Вот два взаимоисключающих цикла sed
:
sed -ne'p;/ 12 * 31 /!d;:n' -e'n;//!bn' <<""
YEAR MONTH DAY RES
1971 1 1 245
1971 1 2 587
...
1971 12 31 685
1971 1 1 245
1971 1 2 587
...
1971 12 31 685
1972 1 1 549
1972 1 2 746
...
1972 12 31 999
1972 1 1 933
1972 1 2 837
...
1972 12 31 343
YEAR MONTH DAY RES
1971 1 1 245
1971 1 2 587
...
1971 12 31 685
1972 1 1 549
1972 1 2 746
...
1972 12 31 999
В основном sed
имеет два состояния - p
rint и eat . В первом состоянии - p
rint state - sed
автоматически p
печатает каждую входную строку, затем проверяет ее по /12 * 31/
образцы. Если текущее пространство образца равно !
не совпадает с d
, и sed
тянет в следующей строке ввода и снова запускает сценарий сверху - по команде p
rint без попытки выполнить что-либо, что следует за командой d
elete вообще.
Если входная строка соответствует /12 * 31/
, однако sed
попадает во вторую половину сценария - цикл eat . Сначала определяется метка ветви :
с именем n
; затем он перезаписывает текущий образец пространство на n
ext, а затем сравнивает текущий образец пространство с //
последним согласованным образцам. Поскольку строка, которая соответствовала ей ранее, только что была перезаписана с помощью n
ext, первая итерация этой eat петли не совпадает, и каждый раз, когда она делает !
не sed
b
возвращается к метке : n
, чтобы получить n
ext входную строку и еще раз сравнить ее с //
последней соответствующего образца.
При окончательном совпадении - некоторые 365 n
ext строки позже - sed
автоматически печатает -n
ot по завершении сценария, тянет в следующей строке ввода и снова начинает с вершины команды p
rint в первом состоянии. Таким образом, каждое состояние цикла будет падать до следующего на тот же ключ и делать как можно меньше в то же время, чтобы найти следующий ключ.
Обратите внимание, что весь сценарий завершается без вызова одной процедуры редактирования и что ему требуется только компиляция одного regexp. Этот результат очень прост - он понимает только
и [^ 123]
. Более того, по крайней мере половина сравнений, скорее всего, будет выполнена без каких-либо компиляций, потому что единственным адресом, на который ссылается цикл eat , является пустой адрес //
. Поэтому sed
может полностью завершить этот цикл одним вызовом regexec ()
для каждой входной линии. sed
может также выполнять аналогичные действия для цикла p
.
Мне было интересно, как различные ответы здесь могут работать, и поэтому я придумал свой собственный стол:
dash <<""
d=0 D=31 IFS=: set 1970 1
while case "$*:${d#$D}" in (*[!:]) ;;
($(($1^($1%4)|(d=0))):1:)
D=29 set $1 2;;
(*:1:) D=28 set $1 2;;
(*[3580]:)
D=30 set $1 $(($2+1));;
(*:) D=31 set $(($1+!(t<730||(t=0)))) $(($2%12+1))
esac
do printf '%-6d%-4d%-4d%d\n' "$@" $((d+=1)) $((t+=1))
done| head -n1000054 >/tmp/dates
dash <<<'' 6.62s user 6.95s system 166% cpu 8.156 total
Это помещает миллион + строк в /tmp/даты
и удваивает выход для каждого из 1970 - 3338 лет. Файл выглядит так:
tail -n1465
3336 12 27 728
3336 12 28 729
3336 12 29 730
3336 12 30 731
3336 12 31 732
3337 1 1 1
3337 1 2 2
3337 1 3 3
3337 1 4 4
3337 1 5 5
3338 12 22 721
3338 12 23 722
3338 12 24 723
3338 12 25 724
3338 12 26 725
3338 12 27 726
3338 12 28 727
3338 12 29 728
3338 12 30 729
3338 12 31 730
... некоторые из них в любом случае.
И затем я попробовал различные команды на нем:
for cmd in "sort -uVk1,3" \
"sed -ne'p;/ 12 * 31 /!d;:n' -e'n;//!bn'" \
"awk '"'{u=$1 $2 $3 $4;if (!a[u]++) print;}'\'
do eval "time ($cmd|wc -l)"
500027
( sort -uVk1,3 | wc -l; ) \
1.85s user 0.11s system 280% cpu 0.698 total
500027
( sed -ne'p;/ 12 * 31 /!d;:n' -e'n;//!bn' | wc -l; ) \
0.64s user 0.09s system 110% cpu 0.659 total
500027
( awk '{u=$1 $2 $3 $4;if (!a[u]++) print;}' | wc -l; ) \
1.46s user 0.15s system 104% cpu 1.536 total
Команды сортировки
и sed
были выполнены менее чем за половину времени awk
- и эти результаты были типичными. Я управлял ими несколько раз. Похоже, все команды также записывают правильное количество строк - и поэтому, вероятно, все они работают.
sort
и sed
были довольно хорошо шея и шея - с sed
обычно волосы впереди - для времени завершения для каждого прогона, но sort
делает больше фактической работы для достижения своих результатов, чем любая из двух других команд. Он выполняет параллельные задания для выполнения своей задачи и получает значительные преимущества от многоядерных процессоров. awk
и sed
оба привязываются к назначенному одноядерному ядру в течение всего времени его обработки.
Результаты здесь из стандартного, актуального GNU sed
, но я попробовал другой. На самом деле, я попробовал все три команды с другими двоичными файлами, но только команда sed
фактически работала с моими инструментами heirloom. Остальные, как я полагаю из-за нестандартного синтаксиса, просто уходят с ошибкой, прежде чем оторваться от земли.
Хорошо использовать стандартный синтаксис, когда это возможно - вы можете свободно использовать более простые, отточенные и эффективные реализации во многих случаях, которые путь:
PATH=/usr/heirloom/bin/posix2001:$PATH; time ...
500027
( sed -ne'p;/ 12 * 31 /!d;:n' -e'n;//!bn' | wc -l; ) \
0.31s user 0.12s system 136% cpu 0.318 total
-121--96733-
Почему grep
? Для поиска используется команда grep
. Вам, кажется, нужно либо вырезать
, либо неловко
, но читаемый builtin также кажется подходящим.
Сравните их:
users | cut -d' ' -f1
users | sed 's/\s.*//'
users | awk '$0=$1'
Если вы хотите сохранить их в переменной, используйте bash:
read myVar blah < <(users)
или:
read myVar blah <<< $(users).
Выше ответ на основе @ manatwork comments .
Para generar solo la última columna de filas que tienen el número máximo de columnas, podría hacer algo como:
who | awk '
NF > max {max = NF; output = ""}
NF == max {output = output $NF ORS}
END {printf "%s", output}'
Para generar una fila por cada fila de entrada, pero vacío para las filas que no tienen el número máximo de columnas:
who | awk '
NF > max {max = NF}
{n[NR] = NF}
NF == max {last[NR] = $NF}
END {for (i = 1; i <= NR; i++) print n[i] == max ? last[i] : ""}'
Si solo desea obtener la última columna si esta columna está disponible, use el hecho de que las líneas que no desea tienen solo cuatro columnas:
who | awk 'NF > 4 { print $NF }'
o, para obtener datos similares,
w -hi | awk '{ print $3 }'
Compruebe si el quinto campo coincide con \(.*\)
e imprímalo si coincide.
who | awk '$5 ~ /\(.*\)/{print $5}'
Si solo está interesado en las direcciones ip
, cambie la expresión regular:
who | awk '$5 ~ /\((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\)/{print $5}'
Si desea el último campo solo de las líneas que tienen la mayor cantidad de campos, deberá leer los datos dos veces :una vez para encontrar la mayor cantidad de campos y otra vez para imprimir los campos. Leer solo una vez no es suficiente :cualquier línea puede tener más campos que las anteriores, y no hay forma de saberlo.
Conawk
(tenga en cuenta que el nombre del archivo se da dos veces):
awk -vfields=0 'FNR==NR {if (NF > fields) fields=NF; next}
NF >= fields { print $NF } NF < fields {print ""}' file file
Si file
contiene
foo bar
one two three four
1 2 3
a b c d
esto imprime el cuarto campo, o vacío para las líneas que no lo tienen:
four d
Eso, por supuesto, no funciona con una tubería, tendrás que usar un archivo temporal.
Una solución alternativa podría almacenar en caché los -campos impresos -hasta que aparezca una línea con más campos, como en la respuesta de Stéphane .