2016-07-07 3 views
2

Я хочу добавить новый элемент в строковую переменную, которая представляет собой список, разделенный запятыми, и предотвращает возможность получения элементов дважды.Добавить элемент в список, разделенный запятыми, с одним слоем

Я придумал этот питона решения:

python -c "import sys ; first = set(sys.argv[1].split(',')) ; all = first.union(set(sys.argv[2:])) ; print ','.join(all)" 1,2 4 3 2 
1,3,2,4 

В нескольких строках:

import sys 
first = set(sys.argv[1].split(',')) 
all = first.union(set(sys.argv[2:])) 
print ','.join(all) 

Хотя решение работает, это не очень хорошо подходит для однострочника в сценарии оболочки ,

Я пробовал пару вещей, используя awk, sed или обычный bash, но ничто не приводит к короткому, но все еще устойчивому решению. У кого-нибудь есть идея, как выразить это с коротким иконом командной строки?

ответ

1

bash option: Сохраните список элементов в строковой переменной (list ниже) с запятыми и запятыми. Таким образом, каждый элемент начинается и заканчивается запятой, что делает вещи намного проще. Для добавления элемента:

new_item=42 # or whatever 
list="${list//,${new_item},/,}${new_item}," 

${list//...} удаляет любые дубликаты (// означает глобальную замену), то ${new_item}, вставляет новый элемент на конец списка. Чтобы добавить несколько элементов:

list=",1,2," 
for x in 4 3 2 ; do list="${list//,$x,/,}$x," ; done 

обирать запятые из списка, вы можете использовать

list="${list#,}" 
list="${list%,}" 

один вкладыш для конкретного примера выше, но распространяется с большим количеством тестовых случаев, будет:

bash -c 'list=",$1,"; shift; for f in "[email protected]"; do list="${list//,$f,/,}$f,"; done; list="${list#,}"; list="${list%,}"; echo $list' -- 1,2 3 4 44 444 1 2 

Обратите внимание, что большая часть этой строки просто получает список из аргументов, а затем выходит на стандартный вывод. Внутри скрипта list="${list//,$x,/,}$x," - это все, что вам нужно.

1

решение Perl:

perl -le 'undef @h{ (split /,/, shift), @ARGV }; $, = ","; print keys %h' 1,2 4 3 2 
0

Использование sed:

echo 1,2 3 2 4 | sed -r ':a {s/([^, ]+)(.*)\1/\2,\1/;ta}; s/ /,/g; s/,+/,/g; s/^,//' 
+0

'эхо 5,4 3 4 5 | sed ... 'выходы', 3,4,5'. –

+0

@JamesBrown Спасибо за подсказку. –

3

awk на помощь!

$ echo -n "1,2 4 3 2" | awk -v RS='[, ]' '!a[$0]++' | paste -sd, 

1,2,4,3 
1

Это не один лайнер, но имо еще чистый раствор оболочки:

#!/bin/bash 
list="1,2" 
new_items="4 5 3" 

for i in $new_items ; do 
    # The `\b` does match at word boundaries 
    ! grep -Eq "\b$i\b" <<< "$list" && list="$list,$i" 
done 
echo "$list" 

Если вы хотите один лайнер от него, вы можете поместить его в функцию:

function add_items() { 
    list="$1" 
    new_items="$2" 
    for i in $new_items ; do 
     ! grep -Eq "\b$i\b" <<< "$list" && list="$list,$i" 
    done 
    echo "$list" 
} 

Зов это нравится:

add_items '1,2' '1 2 3' 
0

Больше AWK:

$ cat test.in 
1,2 3 2 4 
5,4 3 4 5 

$ cat test.in|awk 'BEGIN {FS="[ ,]";OFS=","} {delete a; delete b; n=split($0,a,FS); for(i in a) b[a[i]]=n--; for(i in b) printf "%s%s",i,(b[i]>1)?OFS:ORS}' 
1,2,3,4 
3,4,5 
+0

Это зависит от порядка индекса 'b', соответствующего порядку индекса' a' w.r.t. печать «OFS» или «RS», но это не всегда так. Например, когда я вызываю вашу программу с помощью 'echo '5,4,3 2 1 5 6' | awk ... 'Я получаю' 2,3,4,5 <\n> 6,1, '. – jas

+0

Хмм, не знаю, я получаю '1,2,3,4,5,6'. Я бегаю и зеваю. Что вы делаете (каламбур не предназначен)? –

+0

:-) Mac OS X с родным bsd awk. С gawk у меня нет проблемы с моим предыдущим примером, но он воспроизводится с '$ echo '5,4,3 9 8' | gawk ... '. который дает мне «3,4,5,8 <\n> 9,'. – jas

0

Все больше и больше AWK:

$ echo 1,2 3 2 4|awk 'BEGIN {RS="[ ,\n]";OFS=","} {a[$0]=++i} END {for (j in a) printf "%s%s", j, a[j]<NR?OFS:ORS}' 
1,2,3,4 
Смежные вопросы