shell golf (посоревнуемся?)
Модераторы: /dev/random, Модераторы разделов
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
shell golf
Идея навеяна известной игрой "perl golf" и в частности старой темой нашего давнего хорошего знакомого Сергея Майкова: PERL-GOLF: Первая игра
На первый взгляд наверное может показаться, что на shell может быть не так интересно. Но я в этом усомнился и решил проверить.
Т.к. в отличие от perl, на shell широк выбор орудий для решения задачи, для каждого задания может быть несколько лучших результатов, по одному в каждой номинации:
1. чистый POSIX shell;
2. чистый bash;
3. POSIX shell + POSIX coreutil;
4. bash + GNU coreutils;
5. bash + coreutils + findutils + grep;
6. bash + sed;
7. bash + awk;
8. п. 5 + sed;
9. п. 5 + awk.
Кроме того, если вы найдёте действительно красивое решение с использованием других утилит командной строки, можете опубликовать его вне конкурса. Если другой участник форума сможет улучшить это решение в рамках тех же утилит, стартует дополнительная номинация именно для этого конкурса. Единственное исключение: использование языков программирования, кроме shell, sed и awk, не допускается.
Формальные правила:
1. Ограничений по времени нет. Поэтому победитель -- понятие временное.
2. Пробельные символы, используемые для лучшей читаемости кода, в подсчёте результатов не участвуют.
3. Перевод строки, используемый как разделитель, считается за один символ наравне с ";".
4. Ответы можно публиковать в теме с заданием (для начала, в этой теме; если хорошо пойдёт, тема может быть разделена).
5. Работоспособность ответов проверяется модераторами раздела; неработоспособные ответы могут удаляться в корзину без предупреждения.
На первый взгляд наверное может показаться, что на shell может быть не так интересно. Но я в этом усомнился и решил проверить.
Т.к. в отличие от perl, на shell широк выбор орудий для решения задачи, для каждого задания может быть несколько лучших результатов, по одному в каждой номинации:
1. чистый POSIX shell;
2. чистый bash;
3. POSIX shell + POSIX coreutil;
4. bash + GNU coreutils;
5. bash + coreutils + findutils + grep;
6. bash + sed;
7. bash + awk;
8. п. 5 + sed;
9. п. 5 + awk.
Кроме того, если вы найдёте действительно красивое решение с использованием других утилит командной строки, можете опубликовать его вне конкурса. Если другой участник форума сможет улучшить это решение в рамках тех же утилит, стартует дополнительная номинация именно для этого конкурса. Единственное исключение: использование языков программирования, кроме shell, sed и awk, не допускается.
Формальные правила:
1. Ограничений по времени нет. Поэтому победитель -- понятие временное.
2. Пробельные символы, используемые для лучшей читаемости кода, в подсчёте результатов не участвуют.
3. Перевод строки, используемый как разделитель, считается за один символ наравне с ";".
4. Ответы можно публиковать в теме с заданием (для начала, в этой теме; если хорошо пойдёт, тема может быть разделена).
5. Работоспособность ответов проверяется модераторами раздела; неработоспособные ответы могут удаляться в корзину без предупреждения.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
И для затравки -- первое задание: подсчитать количество символов в реализациях конкурсных заданий, с учётом пп. 2, 3 правил (не забыть про экранирование).
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Сообщения: 438
- Статус: Подопытный участник
Re: shell golf
По поводу пп.2 и 3. Комментарии в подсчете символов, я так понимаю, тоже не учитываются? А ша-банг?
¡ Страсть к разрушению есть творческая страсть!
-
- Бывший модератор
- Сообщения: 5989
- ОС: OS X, openSuSE, ROSA, Debian
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Любых, подпадающих под условия конкурса; чтобы автоматически сравнивать все последущие задания. Я думал, это очевидно.
Нужна небольшая оговорка: конечно, не все пробелы можно убрать автоматически. Например, пробелы внутри одной команды с аргументами предлагаю считать не-убираемыми ("cut -f 2-" -> "cut -f2-" и т.п.). Но многое -- вполне, как то: в начале и в конце строки, вокруг "разделяющих" символов ({};| и т.п.), повторяющиеся (напр. для выравнивания) и пр.
На мой взгляд задачка достаточно интересная. И имеет, навскидку, как минимум два различных алгоритма реализации.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Комментарии -- это очевидно. Ша-банг я сознательно не исключал из учёта, т.к. от его содержимого может зависеть результат (как то #!/bin/sh С вызовом sed внутри; #!/bin/sed; #!/bin/sed -r; и т.п.).Nazyvaemykh писал(а): ↑30.04.2010 10:26По поводу пп.2 и 3. Комментарии в подсчете символов, я так понимаю, тоже не учитываются? А ша-банг?
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Администратор
- Сообщения: 13939
- Статус: oel ngati kameie
- ОС: GNU
Re: shell golf
с пробельными символами внутри экранированных строк, боюсь, в рамках правил конкурса нормально не справиться.
если достаточно просто сокращать набор пробельных символов до одного, то вот такой простенький конгломератик, вроде бы, достаточно точно подсчитывает:
Код: Выделить всё
echo $(($(cat file | sed -r 's/^\s+//;1!s/#.*$//;s/\s+/ /g;/^$/d;s/./1+/g;s/$/1+/')0-1))
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
при сбоях форума см.блог
-
- Администратор
- Сообщения: 5403
- ОС: Gentoo
Re: shell golf
Корректная обработка пробелов - задача, мягко говоря, нетривиальная.
К примеру, здесь есть лишние пробелы:
sed 's/qwe/rty/; s/asd/fgh/'
(после точки с запятой. Если его убрать, sed отработает так же.)
А здесь нет:
echo 's/qwe/rty/; s/asd/fgh/'
поскольку если его убрать, вывод будет другим.
Мало того, аналогичные проблемы есть даже с отступами:
- здесь если убрать отступы, ничего не изменится.
А здесь изменится:
К примеру, здесь есть лишние пробелы:
sed 's/qwe/rty/; s/asd/fgh/'
(после точки с запятой. Если его убрать, sed отработает так же.)
А здесь нет:
echo 's/qwe/rty/; s/asd/fgh/'
поскольку если его убрать, вывод будет другим.
Мало того, аналогичные проблемы есть даже с отступами:
Код: Выделить всё
cat <<-EOT
qwe
rty
EOT
А здесь изменится:
Код: Выделить всё
cat <<EOT
qwe
rty
EOT
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Смотря что значит "справиться". Например, ты с ними, на мой взгляд, не справился: они у тебя сокращаются наравне с неэкранированными.
sash-kan писал(а): ↑30.04.2010 13:34если достаточно просто сокращать набор пробельных символов до одного, то вот такой простенький конгломератик, вроде бы, достаточно точно подсчитывает:выполняться он должен bash-ем.Код: Выделить всё
echo $(($(cat file | sed -r 's/^\s+//;1!s/#.*$//;s/\s+/ /g;/^$/d;s/./1+/g;s/$/1+/')0-1))
Код: Выделить всё
$ echo '" q w e "' >file
$ echo $(($(cat file | sed -r 's/^\s+//;1!s/#.*$//;s/\s+/ /g;/^$/d;s/./1+/g;s/$/1+/')0-1))
9
$ wc -c file
14 file
Код: Выделить всё
tr \\t \ | tr -s ' \n' <file | sed '1!s/#.*$//' | wc -c
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Учитывая ограниченный набор инструментов, допущенных до конкурса, это можно обработать./dev/random писал(а): ↑30.04.2010 14:01Корректная обработка пробелов - задача, мягко говоря, нетривиальная.
К примеру, здесь есть лишние пробелы:
sed 's/qwe/rty/; s/asd/fgh/'
(после точки с запятой. Если его убрать, sed отработает так же.)
А здесь нет:
echo 's/qwe/rty/; s/asd/fgh/'
поскольку если его убрать, вывод будет другим.
Впрочем, думаю, ты прав: "для затравки" задача немного сложновата. Сейчас что-нибудь совсем простенькое придумаю.
/dev/random писал(а): ↑30.04.2010 14:01Мало того, аналогичные проблемы есть даже с отступами:
- здесь если убрать отступы, ничего не изменится.Код: Выделить всё
cat <<-EOT qwe rty EOT
А здесь изменится:
Код: Выделить всё
cat <<EOT qwe rty EOT
Код: Выделить всё
$ cat >f1 <<EOT
> q
> w
> EOT
$ cat >f2 <<-EOT
> q
> w
> EOT
$ diff f1 f2
$ cat >f1 <<EOT
> q
> w
> EOT
$ cat >f2 <<-EOT
> q
> w
> EOT
$ diff f1 f2
$
Для ясности:
Код: Выделить всё
$ $SHELL --version
GNU bash, version 3.2.33(1)-release (arm-unknown-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Администратор
- Сообщения: 5403
- ОС: Gentoo
Re: shell golf
Там должны были быть табы, а не пробелы. Просто их проблематично ввести в браузере.
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Да хотя бы тот же find ! -d, который был в старой теме про perl golf (естественно, варианты 5, 8, 9 здесь исключаются). Или для shell-а это уж слишком простенькое?
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Модератор
- Сообщения: 4823
- Статус: фанат консоли (=
- ОС: GNU/Debian, RHEL
Re: shell golf
а вот тут явный косяк:
сама себя эта команда посчитает некорректно.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
The more you believe you don't do mistakes, the more bugs are in your code.
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
У меня получилось 82 символа если допускать имена с пробелами и 71 если нет. Но выкладывать пока не буду, а то это вообще "тихо сам с собою" получится -- неинтересно.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Администратор
- Сообщения: 13939
- Статус: oel ngati kameie
- ОС: GNU
Re: shell golf
Shell
$ . self
88
$ wc self
1 8 89 self
$ cat self
echo $(($(cat self | sed -r 's/^\s+//;1!s/#.*$//;s/\s+/ /g;/^$/d;s/./1+/g;s/$/1+/')0-1))
$ hexdump -C self
00000000 65 63 68 6f 20 24 28 28 24 28 63 61 74 20 73 65 |echo $(($(cat se|
00000010 6c 66 20 7c 20 73 65 64 20 2d 72 20 27 73 2f 5e |lf | sed -r 's/^|
00000020 5c 73 2b 2f 2f 3b 31 21 73 2f 23 2e 2a 24 2f 2f |\s+//;1!s/#.*$//|
00000030 3b 73 2f 5c 73 2b 2f 20 2f 67 3b 2f 5e 24 2f 64 |;s/\s+/ /g;/^$/d|
00000040 3b 73 2f 2e 2f 31 2b 2f 67 3b 73 2f 24 2f 31 2b |;s/./1+/g;s/$/1+|
00000050 2f 27 29 30 2d 31 29 29 0a |/')0-1)).|
00000059
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
при сбоях форума см.блог
-
- Администратор
- Сообщения: 5403
- ОС: Gentoo
Re: shell golf
find ! -type d:
shopt -s globstar; for i in **; do [ -f "$i" ] && echo "$i"; done
65 символов, или, если убрать ненужные пробелы, 62 символа.
shopt -s globstar; for i in **; do [ -f "$i" ] && echo "$i"; done
65 символов, или, если убрать ненужные пробелы, 62 символа.
-
- Модератор
- Сообщения: 4823
- Статус: фанат консоли (=
- ОС: GNU/Debian, RHEL
Re: shell golf
ну что вы хитрите то (:
вы ша-банг напишите, и увидите, что во второй строке (в которой окажется сед с #) все, что после # просто не посчитается.
Код: Выделить всё
$ cat 1 | wc -c
101
$ cat 1
#!/bin/bash
echo $(($(cat self | sed -r 's/^\s+//;1!s/#.*$//;s/\s+/ /g;/^$/d;s/./1+/g;s/$/1+/')0-1))
$ echo $(($(cat 1 | sed -r 's/^\s+//;1!s/#.*$//;s/\s+/ /g;/^$/d;s/./1+/g;s/$/1+/')0-1))
54
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
The more you believe you don't do mistakes, the more bugs are in your code.
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Не переносимо даже внутри bash: globstar только в bash 4, если память не изменяет. Во всяком случае, ни на одной из доступных мне систем её нет./dev/random писал(а): ↑30.04.2010 18:30find ! -type d:
shopt -s globstar; for i in **; do [ -f "$i" ] && echo "$i"; done
65 символов, или, если убрать ненужные пробелы, 62 символа.
Кроме того, есть одна мелочь: -f и ! -d это не одно и то же.
Моё решение на POSIX shell.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Администратор
- Сообщения: 13939
- Статус: oel ngati kameie
- ОС: GNU
Re: shell golf
да, действительно, некорректно. спасибо за баг-репорт.
зря я выпендрился с удалением комментариев.
учитывая, что вычисление находящегося внутри строки у меня не реализовано, надо было обойтись без этого удаления:
Код: Выделить всё
echo $(($(cat self | sed -r 's/^\s+//;s/\s+/ /g;/^$/d;s/./1+/g;s/$/1+/')0-1))
или, если уж чистым sh + posix coreutils:
echo `cat self | sed -r 's/^\s+//;s/\s+/ /g;/^$/d;s/./1+/g;s/$/1+/'`0-1|bc
кстати, та же самая ошибка (улыбка)
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
при сбоях форума см.блог
-
- Модератор
- Сообщения: 4823
- Статус: фанат консоли (=
- ОС: GNU/Debian, RHEL
Re: shell golf
Блин, 2 символа не дотянул до беспробельных имен:
69 символов:
Код: Выделить всё
ls -lR|sed -n '/^.\//h;G;s/\n/ /;s/:$//;p'|awk '/^-/{print $9"/"$8}'
С одним седом, без ока длиннее получалось. Что-то типа:
Код: Выделить всё
ls -lR|sed -rn '/^.\//h;G;s/\n/ /;s/:$//;/^-/!d;/^-/s_([^ ]*) (\./.*)_\2/\1_;s/.* //;p'
а наличие комментария, в таком случае, достаточно сложно установить.
это ж надо как-то понять, что автор решил напечатать для красоты echo '###result###', а не написал комментарий. (:
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
The more you believe you don't do mistakes, the more bugs are in your code.
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Какие же это coreutils?
Код: Выделить всё
$ dpkg -L coreutils | egrep 'bin/(bc|sed)'
$
Я воспроизвёл один в один, но короче. Если без удаления комментариев, то только ещё короче получится, и без sed:
Код: Выделить всё
tr \\t \ | tr -s ' \n' <file | wc -c
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Администратор
- Сообщения: 13939
- Статус: oel ngati kameie
- ОС: GNU
Re: shell golf
а чёрт их знает, эти posix-ы:
http://www.opengroup.org/onlinepubs/000095...lities/sed.html
http://www.opengroup.org/onlinepubs/000095...ilities/bc.html
что у них там coreutils, а что нет — не знаю.
p.s. в дебиане уж точно не posix coreutils:
$ apt-cache search -n ^coreutils
coreutils - The GNU core utilities
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
при сбоях форума см.блог
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
А с пробелами?SLEDopit писал(а): ↑30.04.2010 19:48Блин, 2 символа не дотянул до беспробельных имен:
69 символов:Код: Выделить всё
ls -lR|sed -n '/^.\//h;G;s/\n/ /;s/:$//;p'|awk '/^-/{print $9"/"$8}'
С одним седом, без ока длиннее получалось. Что-то типа:
Код: Выделить всё
ls -lR|sed -rn '/^.\//h;G;s/\n/ /;s/:$//;/^-/!d;/^-/s_([^ ]*) (\./.*)_\2/\1_;s/.* //;p'
Моё на чистом shell + coreutils:
С пробелами:
Код: Выделить всё
#!/bin/sh
ls -A "$1" | while read i
do i="$1/$i"
[ -d "$i" ] && $0 "$i" || echo "$i"
done
Без:
Код: Выделить всё
#!/bin/sh
for i in `ls -A $1`
do i=$1/$i
[ -d $i ] && $0 $i || echo $i
done
Считал включая sha-bangh. Сейчас сообразил, что можно без него, только перед $0 добавить sh. Итого на шесть символов короче: 65 и 76.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Администратор
- Сообщения: 5403
- ОС: Gentoo
Re: shell golf
В стандарте POSIX термин "coreutils" не фигурирует, если что.
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Насколько я помню, в posix такого нет. Не исключено, что coreutils вообще чисто гнутое понятие (хотя тут уже могу ошибаться). Предлагаю от него и отталкиваться. Потому как если включить всё, что входит в стандарты POSIX, это уже слишком много получится.sash-kan писал(а): ↑30.04.2010 20:53а чёрт их знает, эти posix-ы:
http://www.opengroup.org/onlinepubs/000095...lities/sed.html
http://www.opengroup.org/onlinepubs/000095...ilities/bc.html
что у них там coreutils, а что нет — не знаю.
p.s. в дебиане уж точно не posix coreutils:
$ apt-cache search -n ^coreutils
coreutils - The GNU core utilities
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Администратор
- Сообщения: 13939
- Статус: oel ngati kameie
- ОС: GNU
Re: shell golf
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
при сбоях форума см.блог
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Запишу окончательный вариант, убрав все пробелы.
С пробелами:
Код: Выделить всё
ls -A "$1"|while read i;do i="$1/$i";[ -d "$i" ]&&sh $0 "$i"||echo "$i";done
Без:
Код: Выделить всё
for i in `ls -A $1`;do;i=$1/$i;[ -d $i ]&&sh $0 $i||echo $i;done
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Да за что сподручнее. Номинации для уравнивания шансов просто. Понятно ведь, что на больших задачах shell + coreutils будут почти всегда длиннее, чем sed или awk. Любопытно, что на маленьких пока получается наоборот.
С другой стороны, совсем исключать sed с awk тоже не хотелось: это сильно сузило бы круг задач. Да и башизмы с прочими загогулинами (гнутостями то бишь) -- та же картина. Потому так много разных категорий. Предлагается определять как общего победителя, так и отдельно внутри каждой из номинаций.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Бывший модератор
- Сообщения: 7390
- Статус: думающий о вечном
- ОС: Debian, LMDE
Re: shell golf
Что-то совсем торможу: не sh, а .
-1
64, 75
Без:
-1
64, 75
Код: Выделить всё
ls -A "$1"|while read i;do i="$1/$i";[ -d "$i" ]&&. $0 "$i"||echo "$i";done
Без:
Код: Выделить всё
for i in `ls -A $1`;do i=$1/$i;[ -d $i ]&&. $0 $i||echo $i;done
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
-
- Администратор
- Сообщения: 5403
- ОС: Gentoo
Re: shell golf
Кстати, я предполагал, что это не сохраняется в файл, а вводится в ком. строке, и никакие $0, естественно, невозможны.