Как правильно извлекать различные части `dirname` в сочетании с` find`?

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
1
13.04.2017, 15:36
2 ответа

Вы можете использовать оператор 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 использует сопоставление с образцом на полученные файлы для извлечения частей для замены, и там * будет проходить через / , поэтому (*) вместо ( [^ /] #) будет соответствовать слишком много.

4
27.01.2020, 23:19

Является ли использование только 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
0
27.01.2020, 23:19

Теги

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