Недавно я сделал исполняемый файл bash с разрешениями 722, так как я почти постоянный root. Содержимое файла следующее:

#!/home/nolan/Documents/test/listFiles

[ $# -lt 1 ] && dirFocus = "" || dirFocus = $1
dirSize=$(ls -a $dirFocus | wc -w)

for ((a = 1; a <= $dirSize; a++)) ; do
    i = 1
    for ITEM in $(ls -a $dirFocus); do
        declare -i i
        declare -i a
        if [ $a -eq $i ]; then
            echo "$a : $ITEM"
        fi
        i = $[ $i + 1 ]
    done
done

При запуске в терминале с помощью:

root @ /home/nolan/Documents/test: bash listFiles
1 : .
2 : ..
3 : apple
4 : dirCheck
5 : ifTest
6 : ifTest.txt
7 : listFiles
8 : myscript
9 : nolan.txt
10 : pointer_to_apple
11 : scriptx.sh
12 : Stuff
13 : weekend
14 : weekend2
15 : weekend3

Я получаю этот результат, как и ожидалось. Однако второе я делаю:

root @ /home/nolan/Documents/test: ./listFiles
bash: ./listFiles: /home/nolan/Documents/test/listFiles: bad interpreter: Too
many levels of symbolic links

Ошибка, которую я получаю. Что именно идет не так? Я проверил другие форумы, но они, кажется, не относятся к моей ситуации.

2
Kevin Kruse 10 Авг 2018 в 20:28
Первое предложение вопроса содержит ложь, которая, конечно, является основой ответа.
 – 
JdeBP
10 Авг 2018 в 19:54
2
Разрешения 722 кажутся неправильными. Вы хотите дать миру написать разрешение?
 – 
glenn jackman
10 Авг 2018 в 21:15

2 ответа

Лучший ответ

Первая строка скрипта — это строка «шебанг». Он сообщает ядру (загрузчику программы), какую программу запускать для интерпретации сценария. Ваш сценарий пытается запустить себя для интерпретации сценария, который, в свою очередь, вызывает себя для интерпретации интерпретатора, и так до бесконечности.

Когда вы запускаете скрипт с помощью bash filename, ядро ​​не вызывается, и bash используется для запуска скрипта, который работает.

Ставить

#! /bin/bash

На первую строчку и все будет хорошо.

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

10
choroba 10 Авг 2018 в 19:56
1
То, что что-то продолжается ad infinitum, не очень хорошее объяснение того, почему оно немедленно останавливается с ошибкой. (-:
 – 
JdeBP
10 Авг 2018 в 19:56
"До конца" тогда?
 – 
Kusalananda
10 Авг 2018 в 20:41
Он не выдает ошибку немедленно: «Linux допускает не более BINPRM_MAX_RECURSION, то есть 4 уровня вложенности». (git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/…, хотя в текущих версиях это отличается, может быть эта часть: < a href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/fs/exec.c?h=linux-4.14.y#n1622" rel= "nofollow noreferrer">git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/… ).
 – 
ilkkachu
10 Авг 2018 в 22:57
Это сразу же касается спрашивающего, который описал поведение как происходящее «второе», когда xe попытался это сделать. Вы также сначала смотрите на неправильный код. ENOEXEC не является ошибкой в ​​вопросе.
 – 
JdeBP
11 Авг 2018 в 03:34

хороба очень хорошо объяснил, что ваша проблема связана с тем, что сценарий оболочки использует себя в качестве интерпретатора вместо bash.

Вот предложение по повторной реализации вашего сценария, который

  1. Не содержит синтаксических ошибок (dirFocus = "" является, например, синтаксической ошибкой, поскольку = не должен иметь пробелов вокруг него в назначении).

  2. Работает с именами файлов, содержащими пробелы и новые строки (перебор вывода ls дисквалифицирует любое такое имя файла, аналогично wc -w получит неверный подсчет, если какое-либо имя файла содержит пробелы).

  3. Использует современный синтаксис оболочки ($[ $i + 1 ] является устаревшим синтаксисом bash).

  4. Вводит маленькое улучшение вывода (добавляет (dir) к именам каталогов).

#!/bin/bash

shopt -s dotglob    # make wildcards match hidden names by default
shopt -s nullglob   # make wildcards expand to nothing if no match

count=0
for name in "${1:-.}"/*; do
    count=$(( count + 1 ))
    if [ -d "$name" ]; then
        printf '%d : %s (dir)\n' "$count" "${name##*/}"
    else
        printf '%d : %s\n' "$count" "${name##*/}"
    fi
done

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

${1:-.} означает "использовать то, что находится в $1, если только оно не пусто или не установлено, иначе используйте .".

${name##*/} означает "строка в $name, но без бита до последнего /".

4
Kusalananda 11 Авг 2018 в 11:45
Большое спасибо, чувак, это творит чудеса для меня и моих будущих сценариев! Я играл с одной частью, которую не понял, а именно после "${1:-.}", где за ним следует /*... для чего здесь служит /*? Я понимаю, что если параметра нет, замените на "." но что означает "./*"?
 – 
NolanRudolph
11 Авг 2018 в 07:39
1
* — это символ подстановки имени файла, который соответствует любой строке в имени файла, поэтому в целом ${1:-.}/* заменяется на все имена файлов в каталоге, заданном первым аргументом командной строки, или на все имена файлов в текущем каталог, если аргумент командной строки не указан.
 – 
Kusalananda
11 Авг 2018 в 09:02