Подтвердить что ты не робот

Как хранить файлы каталогов в массиве?

Я пытаюсь сохранить список файлов в массиве, а затем снова пропустить массив. Ниже я получаю, когда я запускаю команду ls -ls с консоли.

total 40
36 -rwxrwxr-x 1 amit amit 36720 2012-03-31 12:19 1.txt
4 -rwxrwxr-x 1 amit amit  1318 2012-03-31 14:49 2.txt

Следующий bash script, который я написал для хранения вышеуказанных данных в массив bash.

i=0
ls -ls | while read line
do
    array[ $i ]="$line"        
    (( i++ ))
done

Но когда я echo $array, я ничего не получаю!

FYI, я запускаю script следующим образом: ./bashscript.sh

4b9b3361

Ответ 1

Попробуйте:

#! /bin/bash

i=0
while read line
do
    array[ $i ]="$line"        
    (( i++ ))
done < <(ls -ls)

echo ${array[1]}

В вашей версии while выполняется в подоболочке, переменные среды, которые вы изменяете в цикле, не видны вне его.

(Имейте в виду, что синтаксический анализ вывода ls обычно не является хорошей идеей вообще.)

Ответ 2

Я бы использовал

files=(*)

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

Ответ 3

Здесь вариант, который позволяет использовать шаблон регулярного выражения для начальной фильтрации, изменить регулярное выражение, чтобы получить необходимую фильтрацию.

files=($(find -E . -type f -regex "^.*$"))
for item in ${files[*]}
do
  printf "   %s\n" $item
done

Ответ 4

Это может сработать для вас:

OIFS=$IFS; IFS=$'\n'; array=($(ls -ls)); IFS=$OIFS; echo "${array[1]}"

Ответ 5

Выполнение любой команды оболочки внутри $(...) поможет сохранить выходные данные в переменной. Таким образом, используя это, мы можем конвертировать файлы в массив с помощью IFS.

IFS=' ' read -r -a array <<< $(ls /path/to/dir)

Ответ 6

Здесь более надежный подход для перебора результатов списка каталогов. Скорее всего, это смысл хранить его в массиве (в соответствии с поставленным вопросом).

Первоначально я тоже хотел получить массив результатов ls, которые я мог бы повторить. Но мой скрипт-прерыватель не поддерживает массивы! На самом деле часто /bin/sh не поддерживает: https://unix.stackexchange.com/info/137566/arrays-in-unix-bourne-shell.

Чтобы решить эту проблему, я написал следующую функцию с методологией "callback"/"function pointer-esque" для общего использования. Я надеюсь, что этот код будет функционировать в большинстве интерпретаторов/дистрибутивов Linux. Самая большая зависимость - это awk, но это почти повсеместно...

Несмотря на то, что вы можете отключить весь код, обратите внимание, это действительно предназначено для того, чтобы быть скрытым в сценарии, который вы "вставляете" в другие как часть "библиотеки". Реализация функции короткая и приятная, обеспечивая при этом массу энергии.

Исходный код

# Fetch a directory list. Callback into a function with each item.
withLs()                                                                        
{                                                                               
    # required arguments
    local usage='Usage: withLs path func [lsOpt] [pass thru values]'                                                                    
    local path=$1; local func=$2;                                               
    if [ -z "${path}" ] || [ -z "${func}" ] ; then                              
        echo ${usage} >&2                                                       
        return 1;                                                               
    fi                                                                          

    # optional ls arguments (respect a convenient "discard argument" option)    
    local lsOpt=$3                                                              
    if [ "${lsOpt}" == "-" ]; then lsOpt=""; fi                                 

    # *all* remaining arguments are gathered into one space delimited variable  
    local passThru=$(echo "[email protected]" | awk '{$1=$2=$3="\b"; printf $0}')              

    # get the directory from the input path
    inputDirPath=$(dirname "${path}")                                                
    if [ ! -d "${inputDirPath}" ] ; then inputDirPath=${PWD}; fi

    # define / manage delimiters & "Internal Field Separator" (IFS)
    local DELIM=';'                                                                                                                  
    local NATURAL_IFS=' '
    local OIFS=$IFS    
    IFS=${NATURAL_IFS} # enforce this so ls & awk work together as expected 

    # Fetch the ls results into a semi-colon delimited string via black magic
    # (i.e. fancy awk scripts). The alternate delimiter retains spaces in 
    # paths. Discard stderr messages for invalid paths, so they simply produce
    # no results, allowing this function to fail gracefully.
    local dirList
    if [ "${lsOpt/R/}" != "${lsOpt}" ]; then 
        # recursive 
        dirList=$(ls -${lsOpt} ${path} 2>/dev/null |  
                 awk -v d=${DELIM} '
                      /:$/&&f{s=$0;f=0}           
                      /:$/&&!f{sub(/:$/,"");s=$0;f=1;next}      
                      NF&&f{printf s"/%s"d,$0}' ) 
    else
        # non recursive (forced when an * may imply recursive)
        if [ "${path/\*/}" != "${path}" ]; then lsOpt=d${lsOpt}; fi
        dirList=$(ls -1${lsOpt} ${path} 2>/dev/null | 
                  awk -v d=${DELIM} '{printf "%s"d,$0}')
    fi

    # change the "internal field separator" and iterate over the items
    IFS=${DELIM}  
    for item in ${dirList}; do 
        if [ ! -z "${item}" ] && # skip any empty or dot items encountered
           [ "${item}" != "." ] && [ "${item}" != ".." ] ; then 

            # get the parent directory & base file/dir name for each item
            entry=$(basename "${item}")
            dirPath=$(dirname "${item}")
            if [ ! -d "${dirPath}" ] ; then dirPath=${inputDirPath}; fi
            if [ "${dirPath}" == "." ]; then dirPath="${PWD}"; fi
            if [ "${dirPath}" != "/" ]; then dirPath="${dirPath}/"; fi

            # invoke the call back!
            ${func} "${dirPath}" "${entry}" ${passThru}
        fi
    done

    # restore the original IFS
    IFS=$OIFS 
}            

Базовый пример

Вот пример того, как это реализовано:

Сначала определите функцию для обратного вызова:

print(){ echo "dir: $1, item: $2"; }

Затем вызовите withLs:

withLs / print

В этом случае я печатаю каждый элемент в корневом каталоге. Функция print вызывается для каждого элемента в списке, получая путь к каталогу в качестве аргумента $1 и элемент списка в качестве аргумента $2 (примечание $1 заканчивается косой чертой, поэтому $1$2 является полным дорожка). Когда я вызываю withLs, я передаю путь для использования с ls для извлечения списка и имя моей функции обратного вызова.

Wildcards

Моя функция поддерживает символы подстановки, но, к сожалению, сценарии оболочки могут приводить к появлению звездочек * в аргументах, если вы не будете осторожны. Если вам нужна звездочка в пути, вы должны избегать ее при вызове функции. Вы можете сделать это, заключив его в кавычки или добавив обратную косую черту \. Поскольку цитирование других магических символов, таких как тильда ~ (т.е. сокращение домашнего каталога), может вызвать проблемы, я рекомендую использовать обратную косую черту. Если вы хотите напечатать элементы в вашем домашнем каталоге с расширением .sh, как вы можете:

withLs ~/\*.sh print

Опции для ls - например, Рекурсия

При желании можно также передать третий аргумент lsOpt, который может содержать любые надстройки для ls, такие как a, для вывода списка скрытых файлов. Таким образом, чтобы распечатать все элементы в домашнем каталоге, в том числе скрытые...

withLs ~ print a

Еще одна мощная опция для ls - это рекурсия, обозначенная буквой "R", например:

withLs ~ print R

При использовании этого режима обратите внимание, что ваша функция обратного вызова будет передавать родительский каталог каждому элементу, так что $1$2 по-прежнему соответствует фактическому полному пути (т.е. $1 может быть дочерним по отношению к каталогу верхнего уровня, в котором выполняется поиск).

Чтобы объединить опции ls, просто запустите их вместе как одну строку, например Ra.

Передайте значения

Наконец, я предоставил открытые значения "пройти через". То есть предоставить другие пользовательские аргументы в ваш обратный вызов. В этом случае print получит дополнительные аргументы "foo" и "bar":

print(){ echo "dir: $1, item: $2, passThru: $3 $4 $5 $6"; }
withLs ~ print - foo bar

Если вы хотите использовать функцию pass thru, но не заботитесь о третьем аргументе (то есть опциях ls), вы можете передать "-" в качестве "заполнителя" (как показано выше).