У когось є сценарій оболонки шаблону для того, щоб щось робити зі 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.White, ви могли б розглянути unaccepting ця відповідь , якщо він не був корисним (або може ввести в оману), так як ви сказали, ви дієте на каталоги. Відповідь Шона Дж. Гоффа має забезпечити більш надійне та дієве рішення вашої проблеми.
lsвихід , ви не повинні читати вихід у forциклі , ви повинні використовувати $()замість `` та використовувати більше котирувань ™ . Я впевнений, що @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кожне повне ім’я буде бачитись як атомна одиниця; це ніяк не розбирає список.
Якщо ви хочете рекурсивно переходити до підкаталогів, це не буде робити, якщо ваша оболонка не має деяких розширених функцій глобалізації (наприклад, bashs 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