Как я рекурсивно получаю все каталоги, содержащие файл txt с тем же именем, что и содержащий каталог в Bash?

Никогда не используйте sudo rm и абсолютный URL-адрес или подстановочный знак, если вы можете ему помочь.

В один прекрасный день у вас будет опечатка и ненависть.

2
задан 17 October 2017 в 06:20

4 ответа

Учитывая

$ tree somepath/
somepath/
├── Dir1
│   ├── Sub1
│   │   └── Sub1.jpg
│   └── Sub2
│       ├── Sub2.jpg
│       ├── Sub2.png
│       └── Sub2.txt
├── Dir2
│   ├── Sub1
│   │   ├── Sub1.doc
│   │   └── Sub1.txt
│   └── Sub2
│       ├── SomeTxt.txt
│       ├── Sub2.jpg
│       └── Sub2.png
├── Dir3
│   └── Dir3.txt
└── Dir4
    ├── Some.txt
    └── Sub1
        └── Dir4.txt

9 directories, 12 files

, тогда, когда опция globstar оболочки включена (shopt -s globstar)

for d in somepath/**/; do
    d="${d%/}"
    [[ -f "${d}/${d##*/}.txt" ]] && printf "%s\n" "$d"
done
somepath/Dir1/Sub2
somepath/Dir2/Sub1
somepath/Dir3

Если вы хотите сохранить приводит к массиву для последующей обработки, вы можете сделать это, используя встроенный mapfile shell (или его синоним readarray), например

mapfile -t TXT_DIRS < <(
  for d in somepath/**/; do
    d="${d%/}"
    [[ -f "${d}/${d##*/}.txt" ]] && printf "%s\n" "$d"
  done
)

ПРИМЕЧАНИЕ. Было бы лучше, завершите список, используя один из методов, описанных в bash: безопасное использование пробелов в поиске в select

Затем вы можете перебирать массив таким же образом

for d in "${TXT_DIRS[@]}"; do
    echo "$d"
done
somepath/Dir1/Sub2
somepath/Dir2/Sub1
somepath/Dir3

может вообще не записывать результаты и просто обрабатывать каждый каталог, как вы его находите, т.е.

for d in somepath/**/; do 
    d="${d%/}"
    [[ -f "${d}/${d##*/}.txt" ]] && echo "Doing something with $d"
done
Doing something with somepath/Dir1/Sub2
Doing something with somepath/Dir2/Sub1
Doing something with somepath/Dir3
3
ответ дан 22 May 2018 в 18:03
  • 1
    Так я бы сделал это TXT_DIR=for d in somepath/**/; do d="${d%/}"; [[ -f "${d}/${d##*/}.txt" ]]; done, чтобы получить переменную? – kingcobra1986 28 September 2017 в 04:28
  • 2
    Вам понадобится синтаксис подстановки подстановки , $(...) i.e. TXT_DIR=$(for d in somepath/**/; do d="${d%/}"; [[ -f "${d}/${d##*/}.txt" ]] && printf "%s\n" "$d"; done). Что вы собираетесь с этим делать? Многострочный текст не всегда очень полезен - массив может быть лучшим вариантом. – steeldriver 28 September 2017 в 05:16
  • 3
    Как бы вы сделали это как массив? В конце концов я хочу выполнить операцию над файлом, который также нуждается в папке. Операция будет такой, как operation original/Dir1/Sub2/Sub2.txt newpath/Dir1/Sub2/Output/ – kingcobra1986 28 September 2017 в 05:44
  • 4
    @ kingcobra1986: в Python: for path in dirs: operation(path, Path('newpath') / path.relative_to(Path('original')).parent / 'Output'), где dirs определено выше – jfs 28 September 2017 в 17:17
  • 5
    @ kingcobra1986 см. обновленный ответ – steeldriver 29 September 2017 в 02:36

Это практически то же самое, что и ответ steeldriver, но он перебирает каждый файл txt вместо каждого каталога.

Поскольку вы упомянули в комментарии, что на самом деле вам не нужен массив, я оставил этот шаг.

shopt -s globstar for f in ./**/*.txt; do d="$(dirname "$f")" if [[ $(basename "$f") == $(basename "$d").txt ]]; then printf '%s\n' "$d" fi done

Выход:

./Dir1/Sub2 ./Dir2/Sub1 ./Dir3
3
ответ дан 24 July 2018 в 18:31

Это практически то же самое, что и ответ steeldriver, но он перебирает каждый файл txt вместо каждого каталога.

Поскольку вы упомянули в комментарии, что на самом деле вам не нужен массив, я оставил этот шаг.

shopt -s globstar
for f in ./**/*.txt; do
    d="$(dirname "$f")"
    if [[ $(basename "$f") == $(basename "$d").txt ]]; then
        printf '%s\n' "$d"
    fi
done

Выход:

./Dir1/Sub2
./Dir2/Sub1
./Dir3
0
ответ дан 22 May 2018 в 18:03

Это практически то же самое, что и ответ steeldriver, но он перебирает каждый файл txt вместо каждого каталога.

Поскольку вы упомянули в комментарии, что на самом деле вам не нужен массив, я оставил этот шаг.

shopt -s globstar for f in ./**/*.txt; do d="$(dirname "$f")" if [[ $(basename "$f") == $(basename "$d").txt ]]; then printf '%s\n' "$d" fi done

Выход:

./Dir1/Sub2 ./Dir2/Sub1 ./Dir3
0
ответ дан 18 July 2018 в 06:07

Другие вопросы по тегам:

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