Как извлечь цифры из строки и сохранить их в переменную?

Параметр --list-onlyне определяет файлы, которые будут переданы; он идентифицирует только те файлы, которые являются кандидатами на передачу. Вы можете увидеть это здесь

touch aa bb cc; ln -s cc dd
rsync --list-only --no-links -a ?? /tmp
rsync -av ?? /tmp

rsync --list-only --no-links -a ?? /tmp

Вывод из последнегоrsync

-rw-r--r--              0 2018/09/05 16:35:01 aa
-rw-r--r--              0 2018/09/05 16:35:01 bb
-rw-r--r--              0 2018/09/05 16:35:01 cc
lrwxrwxrwx              2 2018/09/05 16:35:01 dd -> cc

Рассмотрим последний rsync, где файлы уже перенесены и остаются без изменений на исходнике. Если бы --list-onlyпоказывал файлы, которые необходимо передать, в списке ничего не было бы. Однако он по-прежнему показывает набор исходных файлов, которые необходимо учитывать.

Если вы хотите использовать контекст цели для управления набором файлов, о которых необходимо сообщить, используйте--dry-run --info=name

rsync --dry-run --info=name --archive --no-links ?? /tmp

Или, если вы хотите, чтобы вывод был аналогичен тому, что получается при --list-only(, особенно при исключении типа записи из первого символа)

rsync --dry-run --info=name --out-format='%B%16l %t %f' --archive --no-links ?? /tmp

Начальный вывод

skipping non-regular file "dd"
rw-r--r--               0 2018/09/05 16:42:30 aa
rw-r--r--               0 2018/09/05 16:42:30 bb
rw-r--r--               0 2018/09/05 16:42:30 cc

Последующий вывод после копирования файлов

skipping non-regular file "dd"
2
12.06.2021, 09:23
5 ответов
  1. Для начала вот как получить числовое значение:

    $ echo 'foo = 1700;' | sed -n -e 's/^foo = \([0-9]\+\).*/\1/p'
    1700
    

    Это использует базовые регулярные выражения sedпо умолчанию (BRE ). Вы также можете использовать расширенные регулярные выражения (ERE )с параметром sed -E:

    .
    echo 'foo = 1700;' | sed -n -E -e 's/^foo = ([0-9]+).*/\1/p'
    1700
    

    Вложенное выражение -[0-9]+внутри круглых скобок (... )захватывает еще одну -или -цифру. Это называется «группой захвата» и используется при замене на \1(, которая является первой группой захвата -, если имеется несколько групп захвата, их можно использовать как \1, \ 2, \3 и т. д. ).

    В этом случае сценарий sed пытается заменить всю строку только группой захвата \1 и, если это удалось, вывести измененную строку.

  2. Затем вы хотите преобразовать вывод sedв переменную. Вы делаете это с помощью подстановки команды . например.

    $ myvar=$(echo 'foo = 1700;' | sed -n -E -e 's/^foo = ([0-9]+).*/\1/p')
    $ echo $myvar
    1700
    
  3. Чтобы использовать это в своем скрипте, просто используйте свой файл в качестве аргумента для sed вместо того, чтобы передавать в него echo....

    myvar=$(sed -n -E -e 's/^foo = ([0-9]+).*/\1/p' file)
    
  4. Чтобы обрезать пробелы или справиться со строками, которые могут иметь необязательные начальные пробелы или необязательные пробелы вокруг =и т. д.:

    myvar=$(sed -n -E -e 's/^[[:space:]]*foo[[:space:]]*=[[:space:]]*([0-9]+).*/\1/p' file)
    

    Обратите внимание, что некоторые версии sed (GNU sed, по крайней мере. возможно, другие )понимают perl's\s, так что вы можете сократить это до:

     myvar=$(sed -n -E -e 's/^\s*foo\s*=\s*([0-9]+).*/\1/p' file)
    
7
28.07.2021, 11:25

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

Предполагается, что файл inputявляется:

$ cat input
foo = 1700
foo=17
foo           2000
foobarfoo = 200
foo = foo = 14 243
foo =
200 = foo

Эта gawkкоманда выполнит:

awk '{if(match($0, /\<foo\s*=\s*[0-9]+/)){ 
a=substr($0,RSTART,RLENGTH);sub(/foo\s*=\s*/, "",a); print a}}' input

Или с помощью этой gawkкоманды:

awk '{if(match($0, /\<foo\s*=\s*[0-9]/))
{ l=RLENGTH-1;match($0, /foo\s*=\s*[0-9]+/)
print substr($0,RSTART+l,RLENGTH-l); }}' input

Если шаблон простой, как в foo = 1700, то есть пробел после foo и знак равенства, то указанную выше команду можно сократить:

awk '{if(match($0, /\<foo = [0-9]+/)) print substr($0,RSTART+6,RLENGTH-6);}' input

Другой метод:

awk '/\<foo\s*=\s*[0-9]+/ {print gensub(/(.*)(foo\s*=\s*)([0-9]+)(.*)/, "\\3", "g") }' input

В этой команде все захваченные группы заменяются третьей захваченной группой с использованием обратной ссылки(\\3). gensub()— встроенная функция gawk.

3
28.07.2021, 11:25

Для полноты картины, с grepреализациями, которые поддерживают -oиperl-подобно регулярным выражениям с -P, вы можете сделать:

grep -Po 'foo\s*=\s*\K\d+'

Где:

  • \sсоответствует любому символу пробела
  • *0 или более предшествующих атомов. Например, \s*соответствует 0 или более пробельным символам.
  • \dсоответствует десятичной цифре (, обычно такой же, как [0123456789], но не [0-9], которая часто соответствует гораздо большему количеству символов ).
  • +соответствует одному или нескольким предшествующим атомам.
  • \Kсбрасывает начало согласованной части (what на Keep или, в случае grep -owhat на oвывод ).

Таким образом, будут напечатаны все последовательности из одной или нескольких цифр, которые следуют за foo=, с любым количеством пробелов, допустимых по обе стороны от =, даже если в данной строке встречается более одной цифры.

С помощью pcregrepвы также можете указать число после -o, чтобы напечатать то, что совпадает с группой захвата, а не всю совпадающую часть:

pcregrep -o1 'foo\s*=\s*(\d+)'

Переносимо, вы можете использовать настоящую вещь:perl:

perl -lne 'print $1 for m{foo\s*=\s*(\d+)}g'
3
28.07.2021, 11:25
awk '{for(i=1;i<=NF;i++){if($i ~ /foo/ && $0 ~ /foo.*=.*[0-9]*/){gsub(";","",$(i+2));print $(i+2)}}}' filename

Проверено, работает нормально

1
28.07.2021, 11:25

Предположим, вы хотите выбрать числовое fooзначение,

echo 'foo = 1700;' | awk '$1=="foo" {print $NF+0}'
1700

По умолчанию awkразбивается на пробел (, а не на один пробел ). NF— количество полей, в данном случае 3; $NF— строковое значение третьего поля с пробелами. +0преобразует эту строку 1700;в числовое значение 1700.

Он будет работать с такими строками, как foo = 1700;, но не будет работать со строками, такими как foo=1700;. Из вашего вопроса я не был уверен, были ли вы просто обеспокоены удалением лишних пробелов или что в ваших данных может не быть пробелов и всего остального, а =и ;являются единственными граничными точками. Если вы хотите игнорировать любые пробелы, независимо от того, есть они или нет, вам лучше использовать sed,

echo 'foo=1700;' | sed -n 's/^foo *= *//p' | sed -e 's/;$//' -e 's/ *$//'
1700
3
28.07.2021, 11:25

Теги

Похожие вопросы