:%s/\(\[\[\d\+[_ ]\+Week\([_ ]\+\)\(\d\+\)\)\]\],\(.*\)/\1|Week\2\3,\4]]/
Вы все еще можете улучшить это выражение, дополнив его \s*
там, где это уместно, чтобы лучше обнаруживать несоответствия, которые неизменно возникают в тексте, набираемом вручную.
Некоторые проблемы с предлагаемым вами решением:
Регулярное выражение:\(2018[_\s]Week[_\s]\d\d\),\s\(\d+\w+\)
не совпадает, потому что:
[]
. [_\s]
соответствует символу подчеркивания, обратной косой черты или символу s
. В таких ситуациях вы можете использовать _\|\s
. +
должен быть экранирован, чтобы его особое значение в качестве квантора «1 или более» было активным. В противном случае он соответствует буквальному знаку +
. ,\s\(\d+\w+\)
предшествует последовательность, соответствующая \]\]
в сопоставляемом тексте, но \]\]
отсутствует в шаблоне. Не принимая во внимание проблему с обратной косой чертой в строке подстановки, вы пытаетесь завершить результирующую строку с помощью ]]
, но вы сопоставили только до части, которая указывает день после запятой, используя \d\+\w\+
. Это означает, что если подстановка прошла успешно, ваши строки будут заканчиваться текстом вида :29th]] April through 5th May
,имея последовательность ]]
, которая должна была заканчивать строку где-то посередине.
Строка замены:\[\[\1|\1\2\]\]
не является регулярным выражением, поэтому такие символы, как [
и ]
, экранировать не нужно.
Кроме того, \d\+\w\+
, хотя и не является ошибочным, является избыточным, поскольку \w
уже охватывает все, что делает \d
, и то, как вы указали его контекст с предыдущей частью выражения, всегда соответствует таким вещам, как 9th
и т. д. и никогда не соответствует чему-либо плохому.
РЕДАКТИРОВАТЬ :Очень хорошее предложение от @user1133275: (с некоторыми изменениями )использовать запятую в группе захвата, которая следует за ней в исходном решении, а также изменить строки, где не указан дневной интервал, т.е. нет "xth to yth":
:%s/\(\[\[\d\+[_ ]\+Week\([_ ]\+\)\(\d\+\)\)\]\]\(,.*\)\?/\1|Week\2\3\4]]/
@user1133275 не дал ответа, поэтому я разместил результаты нашего обсуждения в разделе комментариев к этому ответу здесь. Если они решат поместить это в ответ, и я буду уведомлен, я удалю это редактирование, чтобы кредиты могли перейти к автору базовой идеи.
Если написать
find... -exec foo | bar \;
вертикальная черта интерпретируется вашей оболочкой до вызова find
. Левая часть результирующего конвейера — это find... -exec foo
, что, очевидно, приводит к ошибке «отсутствует аргумент для `-exec»; правая сторона трубопровода bar
.
Защита вертикального стержня от корпуса, как в
find... -exec foo \| bar \;
не помогает, потому что первая лексема после -exec
интерпретируется find
как команда и все последующие лексемы, до (, но не включая ), ;
или +
терминатор, принимаются в качестве аргументов этой команды.
См. Понимание опции -exec команды `find`для подробного объяснения.
Чтобы использовать конвейер с -exec
, вам нужно вызвать оболочку. Например:
find./tmp/*/ -name '*.csv' -exec sh -c '
printf "%s %s\n" "$(tail -n +2 "$1" | wc -l)" "$1"' mysh {} \;
Затем, чтобы избежать ошибки «слишком длинный список аргументов», ./tmp/*/
можно переписать как
find./tmp -path './tmp/*/*'...
или, точнее, также исключить tmp
скрытые подкаталоги (, как ./tmp/*/
скорее всего сделал бы по умолчанию ), как
find./tmp -path './tmp/.*' -prune -o -path './tmp/*/*'...
Наконец, вы можете использовать -exec... {} +
более быстрый вариант, который позволяет избежать вызова оболочки для каждого найденного файла. Например, с awk
вместо tail
иwc
:
find./tmp -path './tmp/.*' -prune -o -path './tmp/*/*' \
-name '*.csv' -exec awk '
BEGIN { skip = 1 }
FNR > skip { lc[FILENAME] = (FNR - skip) }
END { for (f in lc) print lc[f],f }' {} +
(Обратите внимание, что awk
также учитывает те искаженные строки, которые не заканчиваются символом новой строки, а wc
не учитывает ).
если все, что вам нужно, это по существу вычесть 1 из каждого wc -l
, это очень просто и чисто:
find [whatever you want] -exec wc -l {} + | perl -pe 's/(\d+)/$1-1/e'