Поиск файлов и печать только их родительских каталогов

У меня есть следующие команды. Где бы ни находился файл .user.log, нам нужно распечатать родительские каталоги (i.e hht и wee1.) Как это можно сделать?

$ cd /nfs//office/ && find . -name '.user.log'
./hht/info/.user.log
./wee1/info/.user.log

Ответ 1

Я что-то пропустил. Конечно, все это регулярное выражение и/или цикл не нужны, один-лайнер выполнит эту работу. Также "для foo в $()" решения не удастся, если в именах путей есть пробелы.

Просто используйте dirname дважды с xargs, чтобы получить родительский родитель...

# make test case
mkdir -p /nfs/office/hht/info
mkdir -p /nfs/office/wee1/info
touch /nfs/office/hht/info/.user.log
touch /nfs/office/wee1/info/.user.log

# parent parent approach
cd /nfs//office/ && find . -name '.user.log' | xargs -I{} dirname {} | xargs -I{} dirname {}

# alternative, have find print parent directory, so dirname only needed once...
cd /nfs//office/ && find . -name ".user.log" -printf "%h\n"  | xargs -I{} dirname {}

Выдает

./hht
./wee1

Ответ 2

for file in $(find /nfs/office -name .user.log -print)
do
    parent=$(dirname $(dirname $file))
    echo $parent
done

ИЗМЕНИТЬ: Простите, что вам нужен каталог grandparent.

Ответ 3

Вы можете легко сделать это с помощью параметров форматирования действия -printf find (см. man find).

cd /nfs//office/ && find . -name '.user.log' -printf "%h\n"
./hht/info
./wee1/info

На странице man:

Screenshot of find manpage

%h\n будет печатать путь для каждого файла в новой строке.

Обратите внимание, что -printf - только GNU. Он не будет работать на macOS (система BSD).

Ответ 4

@trojanfoe имеет правильную идею; this - это просто способ заставить его работать безопасно с любым именем файла и почти любой командой в цикле:

while IFS= read -r -d '' -u 9
do
    echo "$(dirname -- "$(dirname -- "$REPLY")")"
done 9< <( find "/nfs/office/" -name '.user.log' -print0 )

Если вы хотите, чтобы он отображал только уникальные имена:

while IFS= read -r -d '' -u 9
do
    echo "$(dirname -- "$(dirname -- "$REPLY")")"
done 9< <( find "/nfs/office/" -name '.user.log' -print0 ) | sort -u

Ответ 5

find /nfs/office -name '.user.log' | while read line
do
    echo $line | awk -F/ '{print $(NF-1),$NF}'
done

Ответ 6

Вы можете сделать что-то вроде этого:

cd /nfs/office/ && find . -name '.user.log' | xargs -n1 -I{} expr match {} '\(\.\(\/[^/]*\/\)\?\)'

где xargs использует expr match для извлечения части, которая начинается с ., до первого совпадения каталога между косой чертой (/dir/).

Альтернативная версия с использованием sed будет следующей:

cd /nfs/office/ &&  find . -name 'file.txt' | sed -r 's|(\./([^/]*/)?).*|\1|'

Ответ 7

find -type f -exec bash -c 'echo "${1%/*}"' bash {} \;