Bash: Как правильно l oop через каталог и подкаталоги, включая скрытые файлы? - PullRequest
0 голосов
/ 07 февраля 2020

Для школьного задания я пытаюсь рекурсивно провести l oop через каталоги и подкаталоги, чтобы суммировать размер файлов. У меня проблема в том, что конструкция:

for f in ./* ./.*; do
  # summing logic here
done

застревает на f = ./. Он прекрасно работает, шагая в каждый каталог, но как только он попадает в каталог, который он полностью обрабатывает, после последнего файл, f устанавливается на ./.. У меня есть logi c, чтобы проверить, является ли f каталог, который он делает, и затем входит в f, чтобы обработать его. И l oop там навсегда.

Я пытался включить код, чтобы проверить, совпадает ли строка f с “./.” или ”./..”, но она никогда не оценивается как true. Какую ошибку я совершаю?

ОСНОВНОЙ ВОПРОС: Почему if [[ "$f" != "./." ]] || [[ "$f" != "./.." ]]; then не работает и что я могу сделать, чтобы получить тот же результат? Кроме того, если я попробую что-то вроде for f in ./* ./.* ; do echo $f done, я не увижу распечатанные ./. и ./... Как f настраивается на эти значения в моем скрипте?

Я видел ответы на похожие вопросы, которые включают bash -встроенный shopt, но я использую zsh и школьный тест сервер использует csh. Я действительно надеюсь на что-то платформенное c.

Незначительное примечание: поскольку код работает прямо сейчас, назначение выполнено. От нас требуется только суммировать размеры файлов в текущем рабочем каталоге, исключая подкаталоги. Мне было любопытно сделать рекурсивный сценарий, и я делаю только эту часть, чтобы удовлетворить мой интерес. Спасибо за помощь.

#!bin/bash

total_size=0

get_file_size() {
    stat --printf="%s" "$1"
}

add_file_sizes() {
    for f in ./* ./.*; do
        echo "Currently processing: $f"
        if [ -d "$f" ] && [ "$1" == -r ]; then
            echo "$f is a directory"
            if [ "$f" !=  "./." ] || [ "$f" != "./.." ]; then
                echo "$f is not ./. or ./.."
                cd "$f"
                pwd
                add_file_sizes "-r"
                echo "$total_size"
                cd ../
            fi
        fi
        if [ ! -d "$f" ]; then
            echo "$f is not a directory"
            total_size=$((total_size + $(get_file_size "$f")))
            echo "$total_size"
        fi
    done
}

add_file_sizes $1

echo "$total_size"

Редактировать: Вот некоторые выходные данные:

Currently processing: list_size.sh
list_size.sh is not a directory
625
Currently processing: output.txt
output.txt is not a directory
759
Currently processing: test_dir
test_dir is a directory
test_dir is not ./. or ./..
/home/joe/dev/csc60/test_dir
Currently processing: file1
file1 is not a directory
759
Currently processing: file2
file2 is not a directory
759
Currently processing: test_subdir
test_subdir is a directory
test_subdir is not ./. or ./..
/home/joe/dev/csc60/test_dir/test_subdir
Currently processing: file3
file3 is not a directory
759
Currently processing: ./.
./. is a directory
./. is not ./. or ./..
/home/joe/dev/csc60/test_dir/test_subdir
Currently processing: file3
file3 is not a directory
759
Currently processing: ./.
./. is a directory
./. is not ./. or ./..
/home/joe/dev/csc60/test_dir/test_subdir
Currently processing: file3
file3 is not a directory
759
Currently processing: ./.
./. is a directory
./. is not ./. or ./..
/home/joe/dev/csc60/test_dir/test_subdir
Currently processing: file3
file3 is not a directory
759
Currently processing: ./.
./. is a directory
./. is not ./. or ./..
/home/joe/dev/csc60/test_dir/test_subdir
Currently processing: file3
file3 is not a directory
759
Currently processing: ./.
./. is a directory
./. is not ./. or ./..
/home/joe/dev/csc60/test_dir/test_subdir
Currently processing: file3
file3 is not a directory
759
Currently processing: ./.
./. is a directory
./. is not ./. or ./..
/home/joe/dev/csc60/test_dir/test_subdir
Currently processing: file3
file3 is not a directory
759

РЕДАКТИРОВАТЬ 2: Подправил инициал для l oop и в целом улучшен сценарий в ответ на предложение в ответ.

Вывод, когда я изменяю на l oop на for f in * .[!.]*:

Currently processing: list_size.sh
list_size.sh is not a directory
578
Currently processing: list_size_tweaked.sh
list_size_tweaked.sh is not a directory
1156
Currently processing: output_tweaked.txt
output_tweaked.txt is not a directory
1394
Currently processing: output.txt
output.txt is not a directory
1394
Currently processing: test_dir
test_dir is a directory
test_dir is not ./. or ./..
/home/joe/dev/csc60/test_dir
Currently processing: file1
file1 is not a directory
1394
Currently processing: file2
file2 is not a directory
1394
Currently processing: test_subdir
test_subdir is a directory
test_subdir is not ./. or ./..
/home/joe/dev/csc60/test_dir/test_subdir
Currently processing: file3
file3 is not a directory
1394
Currently processing: .[!.]*
.[!.]* is not a directory
1394
stat: cannot stat '.[!.]*': No such file or directory
./list_size_tweaked.sh: line 25: total_size + : syntax error: operand expected (error token is "+ ")
7670

Это, кажется, происходит потому, что в каталоге нет файлов точек, поэтому глобус не ' т расширить.

1 Ответ

2 голосов
/ 07 февраля 2020

Do:

for f in * .[!.]*; do

Я думаю, что это должно работать на любой posix-совместимой оболочке. Документация может быть найдена в Язык команд оболочки Posix 2.13 Обозначение соответствия шаблонов . . соответствует точке, тогда [!.] является выражением с разбивкой по шаблону, которое соответствует всему, кроме точки, поэтому оно фактически исключает . текущий каталог и .. родительский каталог из соответствия.

Примечания :

  • Отличный сценарий, хорошее кодирование, продолжайте в том же духе!
  • Цитируйте расширения переменных, особенно если они являются именами файлов. Не get_file_size $f, а get_file_size "$f". Когда заключать в кавычки переменную оболочки?
  • Не используйте backticks `, их использование не рекомендуется. Вместо этого используйте $(...) везде. Устаревший и устаревший синтаксис bash wiki хакеров .
  • Не используйте function name(), представляет собой смесь двух обозначений оболочки. Просто name() { .. }, чтобы определить функцию, которая совместима с posix и будет работать везде.
  • Просто get_file_size() { stat --printf="%s" "$1"; }. Нет необходимости в переменной и echo.
  • [[ является расширением bash. Так что на csh используйте [. Не забудьте процитировать ваши расширения переменных.
  • Я думаю, я бы find . -type f -printf "%s\n" | awk '{ sum+=$1 } END{print sum}'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...