2016-10-05 3 views
1

Допустим, у меня есть строка из 4 чисел, разделенных пробеломРегулярное выражение для строки чисел

1 4 16 28 
# stored in $ids 

Таким образом, чтобы получить 4 номер отдельно от четырех переменных я использую

id1=$(echo $ids | sed -r "s/([0-9]+){0}([0-9]+) ?.*/\2/g") 
id2=$(echo $ids | sed -r "s/([0-9]+){1}([0-9]+) ?.*/\2/g") 
id3=$(echo $ids | sed -r "s/([0-9]+){2}([0-9]+) ?.*/\2/g") 
id4=$(echo $ids | sed -r "s/([0-9]+){3}([0-9]+) ?.*/\2/g") 

Но проблема в том, что если строка имеет менее 4 чисел, предыдущие числа повторяются.

Например, если строка была

1 

то, что мы получим это

id1=1 
id2=1 
id3=1 
id4=1 

То, что я хочу, что, если есть меньше числа, то дополнительные переменные должны иметь значение 0.

Есть ли способ сделать это?

Примечание: можно использовать только СЕПГ

+2

Вы вообще не можете использовать 'sed'? это даст вам превосходный скрипт, который будет работать быстрее! 'IFS = '' read -ra id_ary <<<" $ ids "; для i в {0..3}; do [[$ {id_ary [i]} = + ([[: digit:]])]] || id_ary [I] = 0; сделанный; id_ary = ("$ {id_ary [@]: 0: 3}") '. На данный момент у вас есть массив 'id_ary', который содержит 4 требуемых номера (если поле не является числом, то оно заменяется на' 0'). –

+0

Почему только 'sed'? когда вы можете использовать собственные методы bash, чтобы добиться этого? – Inian

+0

Проблема в том, что версия bash, в которой работает моя среда, довольно проста и урезана. Многие функции не работают, например, массивы. – Haris

ответ

1

Попробуйте это регулярное выражение вместо она возвращает "", если нет ничего, чтобы вернуться:

$ echo 1 2 3 4 5 6|sed -r "s/^([0-9]+ *){0,3}//g;s/([0-9]+).*/\1/g;s/^$/0/g" 
4 
#     change this latter value^

$ echo 1 2 3|sed -r "s/^([0-9]+ *){0,3}//g;s/([0-9]+).*/\1/g;s/^$/0/g" 
0 
$ 
+0

Да, это действительно работает. Но '' '' не будет работать для меня. Я должен позже проверить каждую переменную и после этого поставить '0'. – Haris

+0

Ну, добавьте это ему: '; s/^ $/0/g'. Отредактировано в ответ. Он заменяет '' '' 'на' 0'. Вероятно, в конце концов тоже не нужно 'g'. –

+0

Спасибо. Оно работает. Не могли бы вы немного объяснить это. – Haris

1

Если вы можете использовать AWK, вы могли бы попробовать что-то вроде этого:

$ awk 'function m(a) { return a ~ /^[0-9]+$/ ? a : 0 } 
    { print m($1), m($2), m($3), m($4) }' 
1 4 16 281 # input 
1 4 16 281 
1   # input 
1 0 0 0 

Функциональные тесты, содержит ли поле одну или несколько цифр, замена с 0 если нет.

Лучший способ получить выходные данные в отдельные переменные зависит от того, что вы планируете делать с ними позже, и версии вашей оболочки.

Используя подстановку процесса, вы можете сделать это:

str='1 4 16 281' 
read -r id1 id2 id3 id4 < <(echo "$str" | awk ' 
    function m(a) { return a ~ /^[0-9]+$/ ? a : 0 } 
    { print m($1), m($2), m($3), m($4) }') 

Менее эффективные, но, возможно, легче понять бы упростить сценарий и запустить его в 4 раза:

id1=$(echo "$str" | awk -v col=1 '{ print $col ~ /^[0-9]+$/ ? $col : 0 }') 
+1

Я не знаю 'awk' правильно. Как я полагаю, чтобы использовать его. Является ли 'a' строковой переменной? – Haris

+0

@Haris Я обновил, чтобы показать несколько способов назначения переменной. –

0

Вы не п eed sed. Это будет работать в любой POSIX-совместимой оболочки:

read -r id1 id2 id3 id4 rest <<EOF 
$ids 0 0 0 0 
EOF 

Это будет работать для любого числа значений в ids. Строка в документе здесь будет содержать не менее 4 значений, независимо от значения ids, и любые дополнительные поля будут назначены rest и могут быть проигнорированы.

Смежные вопросы