Это работает как в bash
(начиная с версии 4.3), так и в ksh93
. Чтобы «придать басу» его, замените весь набор
на локальный
в функциях, а набор
в глобальной области видимости на declare
(тогда как сохраняю все варианты!). Честно говоря, я не знаю, почему в Bash так много разных имен для вещей, которые являются всего лишь вариациями typeset
.
function stack_push
{
typeset -n _stack="$1"
typeset element="$2"
_stack+=("$element")
}
function stack_pop
{
typeset -n _stack="$1"
typeset -n _retvar="$2"
_retvar="${_stack[-1]}"
unset _stack[-1]
}
typeset -a stack=()
stack_push stack "hello"
stack_push stack "world"
stack_pop stack value
printf '%s ' "$value"
stack_pop stack value
printf '%s\n' "$value"
Используя nameref в функции, вы избегаете eval
(мне никогда не приходилось использовать eval
в любом скрипте!). Предоставляя функции stack_pop
место для хранения всплывающего значения, вы избегаете подоболочки.Избегая подоболочки, функция stack_pop
может изменять значение переменной stack
во внешней области видимости.
Подчеркивания в локальных переменных в функции предназначены для того, чтобы избежать ссылки на имя, имя которой совпадает с именем переменной, на которую она ссылается (Bash это не нравится, ksh
не возражает, см. этот вопрос ).
В ksh
вы можете написать функцию stack_pop
, например
function stack_pop
{
typeset -n _stack="$1"
printf '%s' "${_stack[-1]}"
unset _stack[-1]
}
, а затем вызвать ее с помощью
printf '%s %s\n' "${ stack_pop stack }" "${ stack_pop stack }"
( $ {...}
- это То же, что $ (...)
, но не создает подоболочку)
Но я не большой поклонник этого. IMHO, stack_pop
не должен отправлять данные на стандартный вывод, и мне не нужно вызывать его с помощью $ {...}
для получения данных. Я мог бы быть более в порядке с моим исходным stack_pop
, а затем добавить stack_pop_print
, который делает то же самое, если необходимо.
Для Bash вы можете использовать stack_pop
в начале моего сообщения, а затем иметь stack_top_print
, который просто выводит верхний элемент стека в стандартный вывод, не удаляя он (чего не может, потому что он, скорее всего, будет работать в подоболочке $ (...)
).
Вот основная команда, которую вы можете адаптировать к своим индивидуальным потребностям.
awk '{print $0 > $1}' inputfile
РЕДАКТИРОВАТЬ: Извините, я только что понял, что неправильно прочитал ваш вопрос, это неправильный ответ, хотя вы можете достаточно легко «соединить» файлы с пустыми строками
Вот возможное решение
for file in $(awk '{print $1; print $0 > $1}' data.txt | sort | uniq)
do
cat $file
echo
rm $file
done > output.txt
Решение, просто используя awk, если файл предварительно отсортирован:
awk '{a=$1; if (b != "" && a != b) {printf "\n";}; print $0; b = a}' inputfile
Переработано после комментариев don_crissti (спасибо!)
awk '{if (a != "" && a != $1) {printf "\n";}; print $0; a = $1}' inputfile
Решение sed может быть
sed '
/^\n/!{ #if line do not starts from \newline
N #attach next line
/^\(\w\+\b\).*\n\1/! s/\n/\n\n/ #if 1st word not a same insert \newline
}
P #print 1st line (before \newline)
D #remove 1st line, return to start
'
другое решение awk
предполагает сортировку ввода, как показано в примере ввода
$ cat ip.txt
fruit apple word
fruit lemon
fruit orange other word
meat ham word
vegetable salad other
vegetable lettuce more
Примечание. Порядок проверки условий имеет значение.
$ awk '!seen[$1]++ && NR>1{printf "\n"} 1' ip.txt
fruit apple word
fruit lemon
fruit orange other word
meat ham word
vegetable salad other
vegetable lettuce more
Аналогичное решение в perl
$ perl -ane 'print "\n" if !$seen{$F[0]}++ && $. > 1; print' ip.txt
fruit apple word
fruit lemon
fruit orange other word
meat ham word
vegetable salad other
vegetable lettuce more