2009-08-28 17:03:49 +0000 2009-08-28 17:03:49 +0000
101
101

Петля через &007 приводит к bash скрипту оболочки

Есть ли у кого-нибудь шаблонный скрипт оболочки для того, чтобы сделать что-нибудь с ls для списка имен каталогов и петля через каждый из них и сделать что-нибудь?

Я планирую сделать ls для получения списка имен каталогов.

Ответы (7)

120
120
120
2009-08-28 17:09:37 +0000

Присвоено не использовать ls в тех случаях, когда это делает глобус, как предлагают @shawn-j-goff и другие.

Просто используйте петлю for..do..done:

for f in *; do
  echo "File -> $f"
done

Вы можете заменить * на *.txt или любой другой глобус, который возвращает список (файлов, каталогов или чего-либо подобного), команду, которая генерирует список, например, $(cat filelist.txt), или фактически заменить его списком.

В пределах цикла do вы просто ссылаетесь на переменную цикла с префиксом знака доллара (так $f в примере выше). Вы можете echo ее или сделать с ней что угодно еще.

Например, переименовать все .xml файлы в текущем каталоге в .txt:

for x in *.xml; do 
  t=$(echo $x | sed 's/\.xml$/.txt/'); 
  mv $x $t && echo "moved $x -> $t"
done

Или, что еще лучше, если вы используете Bash, вы можете использовать расширение параметров Bash, а не порождать подоболочку:

for x in *.xml; do 
  t=${x%.xml}.txt
  mv $x $t && echo "moved $x -> $t"
done
```.
69
69
69
2012-04-29 22:16:24 +0000

Использование вывода ls для получения имен файлов - плохая идея . Это может привести к сбоям и даже опасным скриптам. Это происходит потому, что имя файла может содержать любой символ, кроме / и null, и ls не использует ни один из этих символов в качестве разделителя, так что если имя файла имеет пробел или новую строку, вы _получите неожиданный результат.

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

Первый - это использование родных глобусных возможностей оболочки.

for dir in */; do
  echo "$dir"
done

Оболочка расширяет */ на отдельные аргументы, которые читает цикл for; даже если в имени файла есть пробел, новая строка или любой другой странный символ, for будет видеть каждое полное имя как атомарную единицу; это никоим образом не анализирует список.

Если вы хотите рекурсивно перейти в подкаталоги, то этого не произойдет, если ваша оболочка не имеет некоторых расширенных глобусных возможностей (таких как bash globstar. Если ваша оболочка не имеет этих возможностей, или если вы хотите убедиться, что ваш скрипт будет работать на различных системах, то следующим вариантом будет использование find.

find . -type d -exec echo '{}' \;

Здесь команда find вызовет echo и передаст ему аргумент с именем файла. Она делает это один раз для каждого найденного файла. Как и в предыдущем примере, нет никакого разбора списка имен файлов; вместо этого имя файла передается полностью как аргумент.

Синтаксис аргумента -exec выглядит немного забавно. find берет первый аргумент после -exec и рассматривает его как выполняющуюся программу, а каждый последующий аргумент - как аргумент, передаваемый этой программе. Есть два специальных аргумента, которые -exec должен видеть. Первый - {}; этот аргумент заменяется именем файла, которое генерируется предыдущими частями find. Второй - ;, который позволяет find знать, что это конец списка аргументов, которые нужно передать программе; find нужен этот аргумент, потому что вы можете продолжить с большим количеством аргументов, которые предназначены для find, а не для исполняемой программы. Причина для [ Использование выводаlsдля получения имен файлов - плохая идея ]&003. Это может привести к сбоям и даже опасным скриптам. Это происходит потому, что имя файла может содержать любой символ, кроме/иnull, иls` не использует ни один из этих символов в качестве разделителя, так что если имя файла имеет пробел или новую строку, вы _получите неожиданный результат.

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

Первый - это использование родных глобусных возможностей оболочки.

for dir in */; do
  echo "$dir"
done

Оболочка расширяет */ на отдельные аргументы, которые читает цикл for; даже если в имени файла есть пробел, новая строка или любой другой странный символ, for будет видеть каждое полное имя как атомарную единицу; это никоим образом не анализирует список.

Если вы хотите рекурсивно перейти в подкаталоги, то этого не произойдет, если ваша оболочка не имеет некоторых расширенных глобусных возможностей (таких как bash globstar. Если ваша оболочка не имеет этих возможностей, или если вы хотите убедиться, что ваш скрипт будет работать на различных системах, то следующим вариантом будет использование find.

find . -type d -exec echo '{}' \;

Здесь команда find вызовет echo и передаст ему аргумент с именем файла. Она делает это один раз для каждого найденного файла. Как и в предыдущем примере, нет никакого разбора списка имен файлов; вместо этого имя файла передается полностью как аргумент.

Синтаксис аргумента -exec выглядит немного забавно. find берет первый аргумент после -exec и рассматривает его как выполняющуюся программу, а каждый последующий аргумент - как аргумент, передаваемый этой программе. Есть два специальных аргумента, которые -exec должен видеть. Первый - {}; этот аргумент заменяется именем файла, которое генерируется предыдущими частями find. Второй - ;, который позволяет find знать, что это конец списка аргументов, которые нужно передать программе; find нужен этот аргумент, потому что вы можете продолжить с большим количеством аргументов, которые предназначены для find, а не для исполняемой программы. Причина для в том, что оболочка также обрабатывает ; специально - она представляет собой конец команды, так что нам нужно экранировать ее так, чтобы оболочка передавала ее в качестве аргумента find, а не потребляла ее для себя; другой способ заставить оболочку не обрабатывать ее специально - заключить ее в кавычки: ';' работает так же хорошо, как и \; для этой цели.

17
17
17
2009-08-28 17:26:27 +0000

Для файлов с пробелами вам необходимо процитировать переменную типа:

for i in $(ls); do echo "$i"; done;

или, вы можете изменить переменную окружения разделителя полей ввода (IFS):

IFS=$'\n';for file in $(ls); do echo $i; done

Наконец, в зависимости от того, что вы делаете, вам могут даже не понадобиться ls:

for i in *; do echo "$i"; done;
5
5
5
2010-08-22 20:02:35 +0000

Если у вас установлена GNU Parallel http://www.gnu.org/software/parallel/ , вы можете сделать так:

ls | parallel echo {} is in this dir

Чтобы переименовать все .txt в .xml:

ls *.txt | parallel mv {} {.}.xml

Посмотрите вводное видео к GNU Parallel, чтобы узнать больше http://www.youtube.com/watch?v=OpaiGYxkSuQ .

4
4
4
2015-02-11 14:36:01 +0000

Просто чтобы добавить к ответу CoverosGene, вот способ перечислить только имена каталогов:

for f in */; do
  echo "Directory -> $f"
done
1
1
1
2012-05-10 22:36:39 +0000

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

(В тестировании у меня были проблемы с установкой IFS на \n, но установка на новую строку работает, как предлагалось здесь):

Например (предполагая, что нужный шаблон поиска ls передается в $1):

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

FILES=($(/bin/ls "$1"))

for AFILE in ${FILES[@]}
do
    ... do something with a file ...
done

IFS=$SAVEIFS

Это особенно удобно в OS X, например, в OS X, для захвата списка файлов, отсортированных по дате создания (от старого к новому), командой ls является ls -t -U -r.

-3
-3
-3
2009-08-28 17:28:24 +0000

Вот как я это делаю, но, наверное, есть более эффективные способы.

ls > filelist.txt

while read filename; do echo filename: "$filename"; done < filelist.txt
```.

Похожие вопросы

6
10
11
37
3