Обман проверки каталога файловой системы Bash

#bash

#bash

Вопрос:

Предполагая, что папки существуют в приведенном ниже сценарии, может кто-нибудь сказать мне, почему это не работает? Я избегаю дополнительных пробелов, чтобы тест работал, но почему-то ему это не нравится без ошибок…

 #!/bin/bash
Base='/tmp/'
Sub='one space/another space/'
declare -a ASub
for argR in "${Sub[@]}"
    do
        Sub =($(printf %q "$argR"))
    done
clear
echo -n $Base
if [ -d  $ExBase ]
    then
        echo "...OK"
    else
        echo "...FAIL"
fi
BaseAndSub=$Base$Sub
echo -n $BaseAndSub
if [ -d  "$BaseAndSub" ]
    then
        echo "...OK"
    else
        echo "...FAIL"
fi
exit 0
  

Комментарии:

1. что вы хотите сделать с этим скриптом?

2. Вы объявляете ASub , но никогда не используете его. Неясно, где вы определяете / инициализируете Sub массив for argR in "${Sub[@]}" . По крайней мере, классически вам нужно было бы использовать BaseAndSub="$Base/$Sub" ; Я бы не стал писать это иначе, хотя это может быть и не на 100% необходимо (но это абсолютно понятно и надежно). Если в имени было несколько смежных пробелов, echo -n $BaseAndSub он теряет их, где echo -n "$BaseAndSub" нет. Используйте двойные кавычки немного более свободно.

Ответ №1:

В этом скрипте много ошибок. ASub объявляется и никогда не используется. ExBase никогда не объявляется, но используется.

Я думаю, это основная проблема: if [ -d $ExBase ]
Поскольку ExBase значение пусто и не задано, оболочка видит это: if [ -d ]
Я ожидал бы синтаксической ошибки, но, по-видимому, оболочка видит «-d» как просто непустую строку и, следовательно, true.

Комментарии:

1. Я использую set -o nounset; set -o errexit в начале всех своих скриптов Bash, которые заставляют Bash останавливаться при подобных ошибках, вместо того, чтобы пропускать их молча.

Ответ №2:

Как сказал @glenn, здесь много ошибок; ASub объявлен, но не используется, Sub иногда используется как строковая переменная, иногда как массив, ExBase используется без установки, …

Основная проблема, однако, заключается в том, что вы выполняете много ненужной (а иногда и разрушительной) работы в попытке обработать пробелы в имени файла, когда все, что необходимо, — это использовать двойные кавычки вокруг всего, что может содержать пробелы. Массивы отлично подходят для хранения списков имен файлов (каждое из которых может содержать пробелы) или командных строк (в аргументах которых могут быть пробелы), но в этом случае у вас есть одно имя файла, поэтому оно не требуется. Добавление кавычек ( printf %q ) почти никогда не бывает полезным, это просто означает, что вы будете искать файлы с фактическими кавычками / экранированием / чем угодно в именах.

Вот моя переписанная версия с удалением ненужного материала и добавлением двойных кавычек в нескольких местах. Я также перешел на более стандартное соглашение о том, чтобы не включать конечные косые черты в имена файлов, поэтому объединение Base и Sub "$Base/$Sub" не просто "$Base$Sub" . Кажется, у меня все работает нормально:

 #!/bin/bash
Base='/tmp'
Sub='one space/another space'
clear
echo -n "$Base"
if [ -d  "$Base" ]
    then
        echo "...OK"
    else
        echo "...FAIL"
fi
BaseAndSub="$Base/$Sub"
echo -n "$BaseAndSub"
if [ -d  "$BaseAndSub" ]
    then
        echo "...OK"
    else
        echo "...FAIL"
fi
exit 0
  

Кстати, при попытке устранения неполадок в сценариях bash очень полезно использовать опцию -x (либо с set -x помощью, либо использовать #!/bin/bash -x в качестве своего shebang ). Это заставляет bash печатать каждую команду перед ее выполнением — с расширенными параметрами, чтобы точно показать, что происходит.