sed -rn '
/typedef struct ([[:alnum:]_]+)\s+\{/!b
s//\1/; h
:X
n
/}\s+([[:alnum:]_]+)/{
s//\1/
H
g
s/;//g
s/(.*)\n(.*)\n(.*)\n(.*)\n(.*)/\1 \5: \2, \3, \4/
p;b
}
s/\s*(.+);\s*/\1/
H
bX
' file
newstruct HashNode: long id, uint32_t vtid, struct HN* next
Вы можете использовать оператор split + glob
:
find . -name '*.zip' -exec sh -c '
IFS=/ # split on /
set -f # disable glob
for file do
set -- $file # invoke split+glob, store in positional parameters
# now the path components are in $1, $2...
mv -i -- "$file" "someString_${2}_${4}+${6}"
done' sh {} +
$ 1
будет иметь .
, $ 2
DE_AT
и так далее. Получить последний аргумент сложно, так как вам понадобится что-то вроде:
eval "last=\${$#}"
Возможно, будет проще использовать другую оболочку, например zsh
, которая имеет для этого подходящие операторы разделения и массивы:
find . -name '*.zip' -exec zsh -c '
for file do
components=(${(s:/:)file})
printf "Last component: %s\n" $components[-1]
mv -i -- "$file" "someString_$components[2]_$components[-3]+$components[-1]"
done' zsh {} +
С помощью zsh
, вы также можете использовать его инструмент пакетного переименования zmv
:
autoload zmv # best in ~/.zshrc
zmv -n '([^/]#)/**/(*)/*/(*.zip)' 'someString_${1}_${2}+$3'
Часть ** /
соответствует любому уровню (включая 0) подкаталогов, поэтому он будет соответствовать (a) / b / c / (d) / e / (f.zip)
или (a) / (b) / c / (d.zip)
с захваченными строками ( a
/ d
/ f.zip
, a
/ b
/ ] d.zip
) в $ 1
/ $ 2
/ $ 3
для замены, чтобы добиться того же поведения, что и для $ Компоненты
, описанный выше.
Часть [^ /] #
, где #
подобна оператору регулярного выражения *
, соответствует любой последовательности не- /.Для глобусов *
работает так же, как *
не может проходить через /
, но после расширения глобуса zmv
использует сопоставление с образцом на полученные файлы для извлечения частей для замены, и там *
будет проходить через /
, поэтому (*)
вместо ( [^ /] #)
будет соответствовать слишком много.
Является ли использование только find
exec
строгим требованием? Я бы предпочел зациклить результаты find
и объединить их с помощью удобного для работы со строками инструмента, такого как awk
:
for ii in $(find . -name "*.zip")
do
mv $ii $(echo $ii|awk -F/ '{print "someString_" $2 "_" $4 "+" $6}')
done
(Замените mv
на ) echo mv
для целей тестирования.)
Примечание: параметр -F /
в awk
устанавливает /
в качестве разделителя вместо пробелов и табуляции.
Как было предложено в комментариях Стефана, вероятно, было бы разумнее и надежнее настроить оператор split + glob
(подробнее об этом здесь ) заранее:
IFS=$'\n'
set -f
Первая строка в любом случае является обязательной, если ваши имена файлов содержат пробелы, и вторая строка, если ваши имена файлов содержат подстановочные знаки.
Не забудьте после этого переключить их на предыдущие настройки, если вы не хотите потом рвать волосы из-за «странного» поведения… Предполагая, что вы не настраивали эти настройки:
unset IFS
set +f