Есть ли у кого-нибудь шаблонный скрипт для работы с lsсписком имен каталогов, циклический просмотр каждого из них и выполнение чего-либо?
Я планирую сделать, ls -1d */чтобы получить список имен каталогов.
Есть ли у кого-нибудь шаблонный скрипт для работы с lsсписком имен каталогов, циклический просмотр каждого из них и выполнение чего-либо?
Я планирую сделать, ls -1d */чтобы получить список имен каталогов.
Ответы:
Отредактировано, чтобы не использовать ls там, где будет делать глоб, как предложили @ shawn-j-goff и другие.
Просто используйте for..do..doneцикл:
for f in *; do
echo "File -> $f"
done
Вы можете заменить *с *.txtили любой другой Glob , который возвращает список (файлов, каталогов или что - нибудь в этом отношении), команда , которая генерирует список, например, $(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
forциклов и типичную ловушку при попытке анализа выходных данных ls. @ DanielA.Белый, вы можете подумать о том, чтобы не принять этот ответ, если он не помог (или потенциально вводит в заблуждение), поскольку, как вы сказали, вы действуете по каталогам. Ответ Шона Дж. Гоффа должен обеспечить более надежное и эффективное решение вашей проблемы.
lsвывод , вы не должны читать вывод в forцикле , вы должны использовать $()вместо `` и Use More Quotes ™ . Я уверен, что @CoverosGene имел в виду хорошо, но это просто ужасно.
lsэто ls -1 | while read line; do stuff; done. По крайней мере, это не сломается для пробелов.
mv -vтобой не надоecho "moved $x -> $t"
Использование вывода lsдля получения имен файлов - плохая идея . Это может привести к неправильной работе и даже опасным сценариям. Это происходит потому , что имя файла может содержать любые символы , кроме /и nullхарактер, и lsне использовать один из этих символов в качестве разделителей, так что если имя файла содержит пробел или символ новой строки, вы будете получать неожиданные результаты.
Есть два очень хороших способа перебора файлов. Здесь я просто echoпродемонстрировал, как что-то делать с именем файла; Вы можете использовать все, что угодно.
Во-первых, использовать встроенные функции оболочки.
for dir in */; do
echo "$dir"
done
Оболочка расширяется */в отдельные аргументы, которые forчитает цикл; даже если в имени файла есть пробел, символ новой строки или любой другой странный символ, forкаждое полное имя будет рассматриваться как атомарная единица; это не разбирает список в любом случае.
Если вы хотите рекурсивно переходить в подкаталоги, то этого не произойдет, если ваша оболочка не имеет некоторых расширенных функций глобализации (например bash, s globstar. Если ваша оболочка не имеет этих функций или если вы хотите убедиться, что ваш скрипт будет работать на различных системах, то следующий вариант заключается в использовании find.
find . -type d -exec echo '{}' \;
Здесь findкоманда вызовет echoи передаст ей аргумент имени файла. Он делает это один раз для каждого найденного файла. Как и в предыдущем примере, нет разбора списка имен файлов; вместо этого имя файла отправляется полностью в качестве аргумента.
Синтаксис -execаргумента выглядит немного забавно. findпринимает первый аргумент после -execи обрабатывает его как программу для запуска, а каждый последующий аргумент - как аргумент для передачи этой программе. Есть два особых аргумента, которые -execнужно увидеть. Первый из них {}; этот аргумент заменяется именем файла, которое findгенерирует предыдущие части . Второй ;, который дает findпонять, что это конец списка аргументов для передачи в программу; findЭто необходимо, потому что вы можете продолжить с дополнительными аргументами, которые предназначены findи не предназначены для программы exec'd. Причина в том \, что оболочка также лечит;специально - она представляет конец команды, поэтому нам нужно избегать ее, чтобы оболочка выдавала ее в качестве аргумента, findа не использовала ее для себя; Другой способ заставить оболочку не обрабатывать ее специально - заключить ее в кавычки: ';'работает так же, как и \;для этой цели.
find. Есть волшебство, которое можно сделать, и даже воспринимаемые ограничения -execможно обойти. -print0Вариант также ценен для использования с xargs.
Для файлов с пробелами вы должны обязательно заключить в кавычки переменную, например:
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;
\nнедостаточен. Никогда не рекомендуется рекомендовать анализ выходных данных ls.
Если у вас установлен 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
Почему бы не установить 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, например, для захвата списка файлов, отсортированных по дате создания (от самого старого до самого нового), lsкоманда имеет вид ls -t -U -r.
\nнедостаточен. Единственные допустимые решения используют цикл for с расширением пути или find.
Вот как я это делаю, но, возможно, есть более эффективные способы.
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done