Другой подход с помощью Bash. Это читает плей-лист в произвольном порядке, пытается вставить строку в другом конце списка, если это - дубликат и откладывает единственную простофилю для перевставки его в другое место. Это перестало работать, если существуют тройные дубликаты (сначала, в последний раз, и отложенный идентичный), и это добавит те плохие записи в самый конец списка. Это, кажется, может решить обширный список, который Вы загрузили большую часть времени.
#!/bin/bash
first_artist=''
last_artist=''
bad_artist=''
bad_line=''
result=''
bad_result=''
while read line
do
artist=${line/ - */}
line="$line"$'\n'
if [ "$artist" != "$first_artist" ]
then
result="$line""$result"
first_artist="$artist"
# special case: first = last
if [ "$last_artist" == '' ]
then
last_artist="$artist"
fi
# try reinserting bad
if [ "$bad_artist" != '' -a "$bad_artist" != "$first_artist" ]
then
first_artist="$bad_artist"
result="$bad_line""$result"
bad_artist=''
bad_line=''
fi
elif [ "$artist" != "$last_artist" ]
then
result="$result""$line"
last_artist="$artist"
# try reinserting bad
if [ "$bad_artist" != '' -a "$bad_artist" != "$last_artist" ]
then
last_artist="$bad_artist"
result="$result""$bad_line"
bad_artist=''
bad_line=''
fi
else
if [ "$bad_artist" == '' ]
then
bad_artist="$artist"
bad_line="$line"
else
# first, last and bad are the same artist :(
bad_result="$bad_result""$line"
fi
fi
done < <(shuf playlist)
# leftovers?
if [ "$bad_artist" != '' ]
then
bad_result="$bad_result""$bad_line"
fi
echo -n "$result"
echo -n "$bad_result"
Это могло быть более умно... в Вашем примере John, John будет обычно придерживаться того, чтобы быть last_artist, потому что это всегда пытается добавить first_artist сначала. Таким образом, если это получает двух других промежуточных художников, не достаточно умно добавить то к началу и другому в конец для ухода от тройного Джона. Таким образом со списками, которые в основном требуют, чтобы любым художником был John, Вы получаете больше отказов, чем Вы должны.
Любая POSIX-совместимая оболочка реализует режим редактирования команд vi
, который можно включить, как ] set -o vi
и отключен, как set + o vi
. Режим редактирования vi
будет различать режимы вставки и команды . Каждое приглашение должно по умолчанию использовать режим ввода , но нажатие клавиши ESC
переключит контексты в режим команды .
Некоторые важные функции этого режима включают:
-L
#
'#'
в начало текущей командной строки и обработайте полученную строку редактирования как комментарий. Эта строка должна быть занесена в историю команд; см. fc
. =
@letter
псевдоним
_letter содержит другие команды редактирования, эти команды должны выполняться как часть вставки. Если псевдоним
_letter не включен, эта команда не будет иметь никакого эффекта. Примечание: эффекты @_ [letter]
рекурсивны, и специальные символы могут быть экранированы для эффекта буквального ввода с помощью CONTROL + V [CHAR]
[count] -
k
или -
будет отступать после максимального количества команд, действующих для этой оболочки (на которую влияет переменная среды $ HISTSIZE
) , терминал должен быть предупрежден, и команда не будет иметь никакого эффекта. [count] y
motion
y
, вся текущая командная строка должна быть перенесена в буфер сохранения. Текущая позиция курсора не изменится. Если счетчик больше, чем количество символов между текущей позицией курсора и концом командной строки, в сторону которого команда движения переместит курсор, это не считается ошибкой; все оставшиеся символы в вышеупомянутом диапазоне должны быть извлечены. Y
[count] p
[count] P
Многие аналогичные эффекты могут быть достигнуты через специфичные для оболочки строковые редакторы (например, bash
readline
команда bind
через ] ~ / .input.rc
или ~ / .editrc
) под лицензией BSD editline
.