LINUX.ORG.RU

Изучаю bash

 


1

1

Я человек далёкий от консоли и программирования настолько, насколько это возможно. Но жизнь заставляет. Решил немного поизучать bash и навелосипедил скрипт, но мозгов не хватает. Зарание извиняюсь за этот ужас и бред:

#!/bin/sh
i=1
f="${1}новая папка"
while [ "-d "$f \($i\)"" = "true" ]
do
  touch "$f \($i\)"
  i=$[$i+1]
done
По идеи код должен принимать первым параметром любой путь, проверять в нём наличие директории «путь/новая папка (1)». Если она есть, проверить «путь/новая папка (2)» и т.д. И если её нет создать её. Но код не работает:
kot@kot-MS-7930:~$ bash -x /home/kot/bin/installin/newfolder.sh /home/kot/bin/
+ i=1
+ f='/home/kot/bin/новая папка'
+ '[' '-d /home/kot/bin/новая' папка '(1)' = true ']'
/home/kot/bin/installin/newfolder.sh: строка 5: [: слишком много аргументов
Видимо я как-то неправильно расставил кавычки. Также я ещё не придумал как начинать проверку не с «нова папка (1)», а с «новая папка». Вроде должно быть не сложно, но все идеи кончились. И ещё вопрос по экранированию символов здесь и здесь в примерах показано, что внутри echo экранирование для $ действует наоборот. А здесь в примере:

\$
придает знаку доллара непосредственное значение (если перед именем переменной стоит \$, то обращения к ее значению не последует)
echo «\$variable01» # $variable01
echo «Стоимость книги \$7.98.» # Стоимость книги $7.98.

показано, что экранирование для $ действует как и везде прямо. Весь мозг сломал…

Я человек далёкий от консоли и программирования настолько, насколько это возможно.

тогда бери python

anonymous ()
#!/bin/bash

set -eu

baseDirPath=$(pwd)

i=1
while true; do
    if [[ ! -d "$dirPath" ]]; then
        dirPath="$baseDirPath/новая папка$i"
        mkdir -p "$dirPath"
        break
    fi
    i=$((i + 1))
done
ProtoH ()
Ответ на: комментарий от KOT040188

Строку там выше надо поднять с $dirPath:

i=1
while true; do
    dirPath="$baseDirPath/новая папка$i"
    if [[ ! -d "$dirPath" ]]; then
        mkdir -p "$dirPath"
        break
    fi
    i=$((i + 1))
done

ProtoH ()
Ответ на: комментарий от anonymous

Иначе ошибку выдавало. Не помню уже что, я подумал () - это служебные символы… Экранировал, ошибка пропала…

KOT040188 ★★ ()
Последнее исправление: KOT040188 (всего исправлений: 1)

Друзья мои, хотелось бы минимальных пояснений. Тема ведь не только для тупо скопировать.

KOT040188 ★★ ()
Ответ на: комментарий от ProtoH

dirPath=«$baseDirPath/новая папка$i»

Перед вторым $ мне пробел нужен, однако…

KOT040188 ★★ ()
Ответ на: комментарий от KOT040188

Есть несколько ошибок:

Семантические и синтаксические:

"-d "$f \($i\)"" = "true"

так получается что ты сравниваешь две строки:
\($i\)""

(это конкатенация литерала \(, значения переменной $i, литерала \) и пустой строки "") и
"true"

а test (это тоже самое, что и []) передаётся слишком много аргументов - 2 аргумента, а она принимает одно выражение, о чём текст ошибки и говорит: первым аргументом передаёшь конкатенацию строки " -d" и значения переменной $f, вторым аргументом - результат сравнения строк - false.

Кавычки вообще для переменных, которые могут хранить пробелы, ими можно склеивать ещё, т.е. так: «$f \($i\)» норм.

Ещё touch создаёт файлы, а не директории.

Логические: ты проверяешь, есть ли директория, и если есть создаёшь её, но нужно (или можно) так: если нет директории, создать и выйти, если есть, то инкрементировать счётчик, используемый для формирования имени директории.

ProtoH ()
Ответ на: комментарий от anonymous

а я копипастил что было, там еще true не нужен , как оказалось

Azmar ()
Ответ на: комментарий от ProtoH

Ещё touch создаёт файлы, а не директории.

Это я уже знаю, но забыл исправить

Логические: ты проверяешь, есть ли директория, и если есть создаёшь её

Читал, что while повторяет цикл пока условие true, то есть пока папка существует проверка будет возвращать true и цикл продолжаться. Когда проверка вернёт false, цикл прервётся и выполнится команда. Я не так понял?

KOT040188 ★★ ()
Ответ на: комментарий от anonymous

F - это переменная. А Пушкин умеет выходить из цикла?

KOT040188 ★★ ()
Ответ на: комментарий от ProtoH

baseDirPath - это что за переменная? Мне же надо задавать путь аргументом…

KOT040188 ★★ ()
Ответ на: комментарий от Azmar

Это переменная. Пушкин как раз-таки до сих пор делает всё за всех в цикле.

KOT040188 ★★ ()
Ответ на: комментарий от Azmar

уже вышел

покажи строку в коде

на второй строке

это оказывается у ТСа эта странная конструкция

anonymous ()
Ответ на: комментарий от KOT040188

где проверка на существование

если путь существует, то mkdir возвращает ненулевой результат

anonymous ()
Ответ на: комментарий от KOT040188
mkdir $1/"новая папка ($i)"

вернет false если директория уже существует. Но на самом деле нет никаких логических false и true, есть команды и статус завершения их работы в виде числа, если это 0 то успешно иначе неуспешно. Есть также команды true и false с соответсвующими статусами завершения.

kazufukurou ()
Ответ на: комментарий от KOT040188

Читал, что while повторяет цикл пока условие true, то есть пока папка существует проверка будет возвращать true и цикл продолжаться. Когда проверка вернёт false, цикл прервётся и выполнится команда. Я не так понял?

Так, частично

цикл прервётся и выполнится команда

какая команда?

Вот из man bash:

       while list-1; do list-2; done
       until list-1; do list-2; done
              The while command continuously executes the list list-2 as long as the last command in the list list-1 returns an exit status of zero.  The until command is identical to the while command, except that the test is negated; list-2 is executed as long as the last command in list-1 returns a non-zero
              exit status.  The exit status of the while and until commands is the exit status of the last command executed in list-2, or zero if none was executed.

Т.е. while будет выполнять команды list-2, пока list-1 возвращает 0. list-1 в данном случае это результат выполнения test expr (test это тоже самое что и [ ]). test возвращает 0 если результат вычисления expr равен true.

f=...
while [ -d "$f \($i\)" ]
do
  mkdir -p "$f \($i\)"
  i=$((i + 1))
done

Буквально код можно прочитать так: пока существует директория «$f \($i\)» создать директорию «$f \($i\)» и увеличить счётчик.

Этот код не работает, т.к:
1. Допустим, что перед первой итерацией цикла, директория «$f \($i\)» существует, тогда сработает mkdir и будет создана та же самая директория, что понятно - пустое действие. На второй итерации, допустим, что директории «$f \($i\)» нет, тогда ничего не будет сделано и цикл завершает работу.
2. Допустим, что перед первой итерацией цикла, директория «$f \($i\)» не существует, тогда ничего не будет сделано.

ProtoH ()
Ответ на: комментарий от kazufukurou

нет проверки на существование без скобочек, мне кажется он это имел в виду

anonymous ()
Ответ на: комментарий от ProtoH

Короче команды возвращают статус 0 при успехе, != 0 при неудаче, если вернули 0, то можно считать что это true в нормальных языках. Статус завершения (целое число) это не тоже самое, что и обычное число 0 или др. целое, т.е. вызов команды, не эквивалентен использованию простого числа вместо вызова. Ну в общем об этом kazufukurou сказал.

Функции в bash тоже кстати можно использовать как обычные команды.

ProtoH ()
Ответ на: комментарий от ProtoH

Буквально код можно прочитать так: пока существует директория «$f \($i\)» создать директорию «$f \($i\)» и увеличить счётчик.

Вот оно что… Понял… Огромное спасибо за такое подробное объяснение. Я оказывается про циклы всё не так понял… baseDirPath - это что за переменная?

KOT040188 ★★ ()
Последнее исправление: KOT040188 (всего исправлений: 2)

Имей ввиду - bash очень полезен для написания скриптов и его легко изучить, но скриптование очень сильно отличается от обычного программирования и знание bash тебе не поможет при изучении другого языка.

Falcon-peregrinus ★★★★★ ()
Ответ на: комментарий от Falcon-peregrinus

Знание баша заставит писать на си (потому что «бже как достало») и питоне («сколько можно так жить, можно куда эффективнее тратить время»). А отличается не так уж сильно, принципы одни и те же.

anonymous ()

Так а по последнему вопросу никто не ответит?

KOT040188 ★★ ()
Ответ на: комментарий от KOT040188

$baseDirPath это базовый путь - директория в которой будут создаваться новые папки, это тоже что и ${1} тут:

f="${1}новая папка"

Только для $baseDirPath предполагается, что это путь, а не префикс для всех папок, которые будут созданы, потому как здесь
        dirPath="$baseDirPath/новая папка$i"

добавляется слеш /.

Можно убрать переменную $baseDirPath, если не нужно, ну и здесь,вместе с /:
        dirPath="$baseDirPath/новая папка$i"

ProtoH ()
Ответ на: комментарий от anonymous
kot@kot-MS-7930:~$ /home/kot/bin/installin/newfolder.sh /home/kot/bin/

Создаётся «новая папка (1)»

kot@kot-MS-7930:~$ /home/kot/bin/installin/newfolder.sh /home/kot/bin/
mkdir: невозможно создать каталог «/home/kot/bin//новая папка (1)»: Файл существует
Создаётся «новая папка ($[i+1])»
mkdir: невозможно создать каталог «/home/kot/bin//новая папка ($[i+1])»: Файл существует
Циклит…

KOT040188 ★★ ()
Ответ на: комментарий от Azmar
kot@kot-MS-7930:~$ /home/kot/bin/installin/newfolder.sh /home/kot/bin/
/home/kot/bin/installin/newfolder.sh: 4: /home/kot/bin/installin/newfolder.sh: Syntax error: Bad for loop variable
KOT040188 ★★ ()
Ответ на: комментарий от ProtoH
kot@kot-MS-7930:~$ /home/kot/bin/installin/newfolder.sh /home/kot/bin/
/home/kot/bin/installin/newfolder.sh: 8: /home/kot/bin/installin/newfolder.sh: dirPath: parameter not set
KOT040188 ★★ ()
Ответ на: комментарий от KOT040188

В итоге ни одного рабочего варианта…

Задача-то какая? Создать следующий каталог из ряда «Новая папка», «Новая папка (1)», «Новая папка (2)», ... в произвольном каталоге? Не уловил проблемы, здесь же тупейшая логика:

#!/bin/bash

newdir_name='Новая папка'

scriptname='mkdir-with-name'
usage=$"Usage: $scriptname <dest>"

err() {
    printf >&2 "$scriptname: $*\n"
    exit 1
}

(($# == 1)) || err "$usage"

dest="$1"

cd "$dest" || exit 1

if [[ ! -e "$newdir_name" ]]; then
    mkdir "$newdir_name"
else
    i=1
    while [[ -e "$newdir_name ($i)" ]]; do
        ((i++))
    done
    mkdir "$newdir_name ($i)"
fi

Или я все-таки неверно уяснил, что́ вам нужно?

Zmicier ★★★★★ ()
Ответ на: комментарий от anonymous

while ! mkdir $1/«новая папка ($i)»

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

Zmicier ★★★★★ ()
Ответ на: комментарий от Zmicier

Верно. Сам каталог задаётся аргументом. Но рабочего варианта пока не было… И ваш вариант не работает:

kot@kot-MS-7930:~$ /home/kot/bin/installin/newfolder.sh /home/kot/bin/
/home/kot/bin/installin/newfolder.sh: 13: /home/kot/bin/installin/newfolder.sh: 1: not found
mkdir-with-name: $Usage: mkdir-with-name <dest>

KOT040188 ★★ ()
Последнее исправление: KOT040188 (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.