Потому что это сопоставление с образцом , а не регулярное выражение.
[[: digit:]] *
означает одну цифру, за которой следует любая строка, поэтому совпало 0b0 / 42
. Это одна цифра 0
, за которой следует строка b0 / 42
.
Теперь в bash
с включенным extglob
вы можете использовать + (список-шаблонов)
для сопоставления одного или нескольких экземпляров шаблона:
$ shopt -s extglob
$ printf '%s\n' "${str/%+([[:digit:]])/5}"
aa/a0b0/5
У вас есть этот синтаксис по умолчанию в ksh
, из которого bash
скопировал.
В zsh
, хотя вы можете использовать эти шаблоны ksh
с setopt kshglob
или использовать zsh
own extendedglob
] ( [[: digit:]] ##
), вы также можете выполнить замену регулярного выражения с помощью функции regex-replace :
$ str="aa/a0b0/42"
$ autoload -U regexp-replace
$ regexp-replace str '[[:digit:]]+$' 5
$ print -rl -- $str
aa/a0b0/5
Если вы убедитесь, что часть после последних номеров /
всегда, вы можете сделать это POSIXly:
printf '%s/%s\n' "${str%/*}" 5
Согласно руководству bash
, вы должны использовать $(< FILE)
, а не $(cat FILE)
. Но нет необходимости использовать подстановку команд:
for some_file in *.md
do
echo -n "$some_file: "
cat $some_file
done
Поскольку вы уже знаете о подстановке процессов, вы также можете сделать что-то вроде:
for some_file in *.md
do
cat <(echo -n "$some_file: ") $some_file
done
Как насчет этого, обрабатывает каждый файл и выводит имя файла с помощью переменной FILENAME.
$ awk '{print FILENAME":",$0}' *.md
bar.md: i am bar
baz.md: i am baz
foo.md: i am foo
$
Или вот это, немного сложнее для глаз, но просто устанавливает $0 в имя файла, за которым следует его содержимое. Действие по умолчанию для awk
- вывести $0, поэтому ему не нужен print
.
$ awk '$0=FILENAME": "$0' *.md
bar.md: i am bar
baz.md: i am baz
foo.md: i am foo
$
Другой подход. Вместо использования FILENAME используется массив аргументов ARGV.
$ awk '$0=ARGV[++z]": "$0' *.md
bar.md: i am bar
baz.md: i am baz
foo.md: i am foo
$