1

Я пытаюсь написать скрипт bash, который подсчитывает все файлы в данном каталоге и подкаталогах, поэтому я написал это:

#!/bin/bash

var=0
if ["$#" == "0"]
    directory="$(echo pwd)"
  then
    directory=$1
fi

echo $directory;
for x in `ls -l $directory | grep "^-" | tr -s ' ' | cut -d ' ' -f 9`;
do
var=$((var+1))
done

for x in `ls -l $directory | grep "^d" | tr -s ' ' | cut -d ' ' -f 9`;
do
output = "$($0 $x)"
done

var=$((var+output))
echo $var

Но я получаю что-то вроде этого:

./lala2
./lala2: line 4: [0: command not found

test
./lala2: line 4: [1: command not found
./lala2: line 4: [1: command not found

Это почему? Являются ли переменные глобальными?

1 ответ1

3

Заменить:

if ["$#" == "0"]

с:

if [ "$#" = "0" ]

Некоторые комментарии:

  1. В оболочке пробелы важны. Если вы хотите, чтобы оболочка распознала тестовую команду, [ , вокруг [ . Должны быть пробелы.

    Пробелы не важны для ключевых слов оболочки, но [ , в отличие от [[ , это команда, а не ключевое слово.

  2. Значение сообщения об ошибке [0: command not found состоит в том, что значение "$#" равно 0, поэтому строка ["$#" стала [0 и bash не смог найти команду с именем [0 .

  3. Можно использовать == для равенства строк в bash. Это, однако, не портативный. В POSIX правильным оператором равенства в [...] является = . Это становится очень важным, если вы запускаете свой скрипт, преднамеренно или непреднамеренно , под оболочкой POSIX, такой как dash .

Другие вопросы

  1. Еще раз, пробелы имеют значение. Когда оболочка видит эту команду:

    output = "$($0 $x)"
    

    он попытается выполнить команду с именем output и предоставить ей два аргумента, первый из которых = а второй - результат "$($0 $x)" . Следовательно, как указывает Гордон Дэвиссон, эту строку следует заменить на:

    output="$($0 $x)"
    

    Поскольку вокруг = нет пробелов, оболочка будет воспринимать это как присвоение переменной.

  2. Скрипт пытается проанализировать вывод ls и это ненадежно . В этом случае это приведет к ошибкам, если какое-либо из имен подкаталогов будет содержать пробелы.

  3. Как указывает rici, команда directory="$(echo pwd)" скорее всего, не делает то, что вы ожидаете. Заметим:

    $ directory="$(echo pwd)"
    $ echo "$directory"
    pwd
    

    Эта команда назначает строку pwd directory переменных. Возможно, вам нужен текущий рабочий каталог, например так:

    directory=$(pwd)
    

    Но это проще, чем это. В Unix текущий рабочий каталог всегда .:

    directory=.
    
  4. Существуют и другие причины, по которым это утверждение if-then не соответствует ожиданиям:

    if ["$#" == "0"]
        directory="$(echo pwd)"
      then
        directory=$1
    fi
    

    Вы, вероятно, хотите переместить оператор then и добавить оператор else:

    if [ "$#" = "0" ]
    then
        directory=.
    else
        directory="$1"
    fi
    

Альтернативный скрипт

Если целью является подсчет количества обычных файлов в каталоге и всех его подкаталогах, попробуйте:

echo "$(find "$directory" -type f -printf "1\n" | wc -l)"

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .