- #!/bin/sh
- Рекурсивные операции с файлами в Linux
- Эпиграф
- chmod
- chown, chattr, chgrp
- rm, grep
- Прочие команды
- Заключение
- Постскриптум
- 2 комментария
- Как рекурсивно изменить права доступа к файлу в Linux
- Chmod Рекурсивный
- Использование команды find
- Выводы
- Почему -r рекурсивно необходимо при копировании каталога в Linux?
- Bash-скрипты, часть 6: функции и разработка библиотек
- Объявление функций
- Использование функций
- Использование команды return
- Запись вывода функции в переменную
- Аргументы функций
- Работа с переменными в функциях
- ▍Глобальные переменные
- ▍Локальные переменные
- Передача функциям массивов в качестве аргументов
- Рекурсивные функции
- Создание и использование библиотек
- Вызов bash-функций из командной строки
- Итоги
#!/bin/sh
Линуксоид на велосипеде с моторчиком
Рекурсивные операции с файлами в Linux
Иногда возникает путаница между опциями -r и -R, каждая из которых в разных программах может означать рекурсивную обработку файлов в найденных каталогах. А может означать нечто совершенно противоположное или работать не так, как этого ожидал пользователь. Попробуем разобраться, в каких случаях что используется.
Эпиграф
— Это новый «Гарри Поттер». Я заказал версии для детей и взрослых, чтобы проверить, что в тексте нет различий.
Морис Мосс, The IT Crowd.
chmod
Ключ -r у chmod интерпретируется как «запретить всем чтение файла», а 755 в данном случае рассматривается как название файла, у которого изменяются права. Поскольку в подавляющем большинстве случаев файла с таким названием в текущей директории отсутствует, то команда возвращает ошибку.
chown, chattr, chgrp
У вышеперечисленных команд опция -r просто отсутствует. Для рекурсивной обработки директорий необходимо использовать опцию -R. Очевидно, так сделано из солидарности с «братской» командой chmod
Несмотря на то, что в странице документации cp из GNU coreutils сказано, что опции -r и -R равнозначны и означают рекурсивную обработку встречающихся директорий, опция -r, в отличие от -R, не соответствует стандарту POSIX и ее указание может повлечь за собой неожиданные последствия в случае, если очередной копируемый объект является чем-то отличным от обычного файла или директории (например, символической ссылкой, fifo или сокетом). В таких случаях некоторые реализации cp просто копируют содержимое ссылки/fifo, тогда как при -R такие объекты пересоздаются заново. Раньше такое поведение было присуще GNU cp, о чем до сих пор имеется свидетельство в русском man cp. Что касается более правильных (чем Linux) систем, то, например, в BSD-версии cp опция -r работает в «режиме совместимости», т.е. не создает символическую ссылку заново, а копирует содержимое в файл с тем же именем.
Ключ -r команды ls означает «обратный порядок сортировки»
Правильно:
rm, grep
Зато в следующих случаях употребление -r/-R равнозначно:
Что касается grep, то, во-первых, обе опции не соответствуют POSIX (но, похоже, присутствуют во всех реализациях) Во-вторых, иногда возникает путаница между опциями -i (игнорировать регистр) и -I (пропускать двоичные файлы). Но это уже тема для другого разговора 🙂
Прочие команды
Поскольку команд, в том или ином виде поддерживающих рекурсивную обработку каталогов, набралось довольно много, то я попробовал свести их в одну таблицу.
команда | -r | -R |
---|---|---|
chacl | рекурсия | удаление ACL только с файлов |
setfacl | не поддерживается | рекурсия |
cvs | номер ревизии | рекурсия |
diff | рекурсия | не поддерживается |
gzip/gunzip | рекурсия | не поддерживается |
zip | рекурсия | рекурсия, начиная с текущей директории (см. man zip, там есть существенная разница в обработке -r и -R) |
rsync | рекурсия | использование относительных путей |
wget | рекурсия | указывает список отвергаемых шаблонов |
Заключение
Как видно, в большинстве случаев для указания рекурсии используется опция -r в нижнем регистре, в противовес стандартным утилитам, для которых характерно все же -R. Поэтому совет один: в случае сомнения смотрите в man, там все написано 🙂
Постскриптум
По абзацу про cp видно, что русская документация в некоторых дистрибутивах (не будем показывать пальцем на Debian и Ubuntu) не соответствует реальному положению дел. В частности, несмотря на то, что в jaunty используется GNU coreutis 6.10, русский man описывает cp версии 4.1. Желающие могут самостоятельно сравнить свою версию man 1 cp с локализованной. Другими словами, русская страница документации cp в силу своей древности вводит пользователя в заблуждение, т.е. врёт. По этой причине я рекомендую сделать apt-get remove manpages-ru.
2 комментария
- Comment by anon :
> По этой причине я рекомендую сделать apt-get remove manpages-ru
Плюсую. Помню как потерял с час времени, из за феерично переведенного мана:
If from is not NULL, and the underlying protocol provides the source address, this source address is filled in.
Если параметр from не равен NULL, а сокет не является ориентированным на соединения, то адресотправителя в сообщении не заполняется.
scp неплохо было бы упомянуть. Нигде проблем с -r/-R не испытывал, только в scp почему-то постоянно пишу -R.
Источник
Как рекурсивно изменить права доступа к файлу в Linux
Если вы используете Linux в качестве основной операционной системы или управляете серверами Linux, вы столкнетесь с ситуацией, когда попытаетесь создать или отредактировать файл и получите ошибку «Permission deny». Как правило, ошибки, связанные с недостаточными разрешениями, можно решить, установив правильные права доступа или владельца .
Linux — это многопользовательская система, и доступ к файлам контролируется с помощью разрешений, атрибутов и владельцев файлов. Это гарантирует, что только авторизованные пользователи и процессы могут получить доступ к файлам и каталогам.
Для получения дополнительной информации о правах доступа к файлам см. «Команда Umask в Linux» .
В этой статье мы объясним, как рекурсивно изменять права доступа к файлам и каталогам.
Chmod Рекурсивный
Команда chmod позволяет изменять права доступа к файлам в символьном или числовом режиме.
Чтобы рекурсивно работать со всеми файлами и каталогами в данном каталоге, используйте команду chmod с параметром -R , ( —recursive ). Общий синтаксис для рекурсивного изменения прав доступа к файлу следующий:
Например, чтобы изменить права доступа для всех файлов и подкаталогов в каталоге /var/www/html на 755 вы должны использовать:
Режим также можно указать с помощью символьного метода:
Только root, владелец файла или пользователь с привилегиями sudo могут изменять права доступа к файлу. Будьте особенно осторожны при рекурсивном изменении разрешений файлов.
Использование команды find
Как правило, файлы и каталоги не должны иметь одинаковые разрешения. Большинству файлов не требуется разрешение на выполнение, тогда как вы должны установить разрешения на выполнение для каталогов, чтобы изменить их.
Наиболее распространенный сценарий — рекурсивное изменение разрешений файла веб-сайта на 644 и разрешений каталога на 755 .
Команда find ищет файлы или каталоги в /var/www/html и передает каждый найденный файл или каталог команде chmod для установки разрешений.
При использовании find с -exec команда chmod запускается для каждой найденной записи. Используйте команду xargs чтобы ускорить операцию, передав сразу несколько записей:
Выводы
Команда chmod с параметрами -R позволяет рекурсивно изменять права доступа к файлу.
Чтобы рекурсивно установить разрешения для файлов в зависимости от их типа, используйте chmod в сочетании с командой find .
Если у вас есть какие-либо вопросы или отзывы, не стесняйтесь оставлять комментарии.
Источник
Почему -r рекурсивно необходимо при копировании каталога в Linux?
У меня вопрос: почему -r при создании копии каталога необходимо использовать флаг (рекурсивный)? Т.е. зачем это делать:
Когда бы я не хотел такого поведения при копировании каталога?
Разве рекурсивная копия каталога не является поведением по умолчанию; поведение мы хотим почти все время?
Такое ощущение, что это лишний флаг.
Как работают файловые системы, каталог — это на самом деле не папка, содержащая файлы, а каталог — это файл, который содержит указатели на узлы «дочерних» файлов, связанных с ним. Это означает, что с точки зрения файловой системы файл — это файл, а каталог — это просто файл, содержащий список подключенных файлов.
Итак, с точки зрения командной строки, делая это:
В основном означало бы скопировать указанный файл dir1 в новый файл с именем copyDir1 . А что касается файловой системы, то dir1 в любом случае это просто файл; тот факт, что это «каталог», будет очевиден только тогда, когда файловая система на самом деле проверяет, dir1 что это за куча битов на самом деле.
-r Флаг указывает файловую систему рекурсивно скатываются файл / дерево каталогов и копировать любые и все содержимое , которое может быть «ребенок» из этого файла на новое место.
Теперь о том, почему это может показаться излишним или избыточным, это действительно сводится к историческим методам работы с файловыми системами. А также создание системы, которая защищена от всех типов ошибок, связанных с пользователем; случайный, а также преднамеренный.
То есть, допустим, у вас есть
/bin файл в вашем домашнем каталоге, который вы хотите скопировать, но случайно пропустили —
потому что вы человек и делаете ошибки — так оно /bin и есть:
С «сетью безопасности», /bin являющейся каталогом в сочетании с необходимостью -r флага, вы избежите случайного копирования всего двоичного корня системы, в которой вы находитесь, в ваш домашний каталог. Если бы эта сеть безопасности не существовала, произошла бы небольшая или, возможно, крупная катастрофа.
Логика здесь заключается в том, что в дни, предшествующие GUI (графические пользовательские интерфейсы), необходимо устанавливать логические / поведенческие соглашения, чтобы избежать создания пользователем ошибок, которые могут потенциально убить систему. И использование -r флага теперь является одним из них.
Если это кажется излишним, то не нужно смотреть дальше, чем современная система графического интерфейса, которую можно поместить над файловыми системами Linux. Графический интерфейс пользователя решает основные пользовательские проблемы, такие как эта, позволяя легко перетаскивать файлы и каталоги.
Но в случае текстовых интерфейсов большая часть «пользовательского опыта» в этом мире — это, в основном, просто логические и основанные на практических условиях дорожные неровности, которые помогают держать пользователя под контролем, чтобы предотвратить потенциальную катастрофу.
Точно так же именно поэтому файловые системы Linux / Unix не имеют 777 разрешений и sudo прав, установленных по умолчанию, и то, как настоящие системные администраторы вздрагивают, когда пользователь устанавливает 777 разрешения или предоставляет всем sudo права. Это основные вещи, которые нужно сделать, чтобы система была стабильной и как можно более «пользовательской»; любой, кто поспешит заморозить эти соглашения, скорее всего, нанесет ущерб их системе, даже не подозревая об этом.
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: Другой ответ здесь, на сайте Unix Stack Exchange, дает хорошее объяснение того, почему нерекурсивная копия каталога является проблематичной; Акцент мой.
Что ж, без флага -R возможно только копирование файлов, потому что довольно необычно, что кто-то хочет нерекурсивно копировать каталог: нерекурсивная копия просто привела бы ко второму имени для каталога, указывая непосредственно на та же структура каталогов. Поскольку это редко то, что люди хотят, и на самом деле существует отдельная программа, которая делает это (ln), нерекурсивная копия каталогов не допускается.
Таким образом, если каталог — это просто файл с элементами inode, создание прямой копии этого файла будет эквивалентно тому, как будет работать жесткая ссылка. Который не тот, кто хочет.
/bin . Сам флаг не предотвращает ошибок и не обязательно делает кого-то лучше, когда он осторожен. Если вы хотите предотвратить ошибки, команда cp может так же легко посмотреть на рассматриваемый узел и выдать подсказку, что-то вроде «Это каталог, хотите ли вы скопировать все содержимое в указанное место (y / п)?» Это было бы защитной сеткой . Требование -r для каталогов удерживает поток кода больше, чем что-либо еще.
Это правда, что такое поведение мы хотим почти все время. Однако это не обязательно означает, что рекурсивное копирование должно быть поведением по умолчанию.
Я думаю, что причины cp действуют так, как это имеет корни в философии Unix . Unix предпочитает программы, которые делают одно и делают это хорошо , а также программы, которые просты как по интерфейсу, так и по реализации (иногда их называют хуже, лучше ).
Ключевой частью головоломки здесь является понимание того, что cp не копирует каталоги — cp копирует файлы (и только файлы). Если вы хотите скопировать каталог, cp вызывайте себя рекурсивно , чтобы скопировать файлы в каждый каталог.
Конечно, с точки зрения пользователя, разница между «копированием каталогов» и «рекурсивным копированием файлов» абсолютно ничтожна, но наличие этого интерфейса помогает реализации оставаться простой .
Если вы cp сможете копировать каталоги, у вас скоро появится желание добавить больше функций, которые имеют смысл только для каталогов — например, вы можете захотеть копировать только имена файлов, оканчивающиеся на .sh . Это неизбежно приводит к раздутию и сбою функций, к которым мы привыкли в других операционных системах, что делает программное обеспечение медленным, сложным и подверженным ошибкам.
Другое преимущество заключается в том, что наличие -r также помогает пользователю понять, что на самом деле происходит под интерфейсом. Приятным побочным эффектом этого является то, что изучение концепции рекурсивной операции избавит вас от некоторой работы, когда вы узнаете о других инструментах, которые ее поддерживают (например grep , например).
Некоторые люди наверняка скажут вам, что предоставление подробностей реализации пользователю плохо , а наличие дополнительных функций — это хорошо . Мое намерение здесь — просто объяснить причину такого поведения, поэтому я не буду спорить в любом случае.
Источник
Bash-скрипты, часть 6: функции и разработка библиотек
Занимаясь разработкой bash-скриптов, вы рано или поздно столкнётесь с тем, что вам периодически приходится использовать одни и те же фрагменты кода. Постоянно набирать их вручную скучно, а копирование и вставка — не наш метод. Как быть? Хорошо бы найти средство, которое позволяет один раз написать блок кода и, когда он понадобится снова, просто сослаться на него в скрипте.
Оболочка bash предоставляет такую возможность, позволяя создавать функции. Функции bash — это именованные блоки кода, которые можно повторно использовать в скриптах.
Объявление функций
Функцию можно объявить так:
Функцию можно вызвать без аргументов и с аргументами.
Использование функций
Напишем скрипт, содержащий объявление функции и использующий её:
Здесь создана функция с именем myfunc . Для вызова функции достаточно указать её имя.
Результаты вызова функции
Функцию можно вызывать столько раз, сколько нужно. Обратите внимание на то, что попытавшись использовать функцию до её объявления, вы столкнётесь с ошибкой. Напишем демонстрирующий это скрипт:
Как и ожидается, ничего хорошего после его запуска не произошло.
Попытка воспользоваться функцией до её объявления
Придумывая имена для функций, учитывайте то, что они должны быть уникальными, иначе проблем не избежать. Если вы переопределите ранее объявленную функцию, новая функция будет вызываться вместо старой без каких-либо уведомлений или сообщений об ошибках. Продемонстрируем это на примере:
Как видно, новая функция преспокойно затёрла старую.
Использование команды return
Команда return позволяет задавать возвращаемый функцией целочисленный код завершения. Есть два способа работы с тем, что является результатом вызова функции. Вот первый:
Команда echo вывела сумму введённого числа и числа 10.
Вывод значения, возвращаемого функцией
Функция myfunc добавляет 10 к числу, которое содержится в переменной $value , значение которой задаёт пользователь во время работы сценария. Затем она возвращает результат, используя команду return . То, что возвратила функция, выводится командой echo с использованием переменной $? .
Если вы выполните любую другую команду до извлечения из переменной $? значения, возвращённого функцией, это значение будет утеряно. Дело в том, что данная переменная хранит код возврата последней выполненной команды.
Учтите, что максимальное число, которое может вернуть команда return — 255. Если функция должна возвращать большее число или строку, понадобится другой подход.
Запись вывода функции в переменную
Ещё один способ возврата результатов работы функции заключается в записи данных, выводимых функцией, в переменную. Такой подход позволяет обойти ограничения команды return и возвращать из функции любые данные. Рассмотрим пример:
Вот что получится после вызова данного скрипта.
Запись результатов работы функции в переменную
Аргументы функций
Функции bash можно воспринимать как небольшие фрагменты кода, которые позволяют экономить время и место, избавляя нас от необходимости постоянно вводить с клавиатуры или копировать одни и те же наборы команд. Однако, возможности функций гораздо шире. В частности, речь идёт о передаче им аргументов.
Функции могут использовать стандартные позиционные параметры, в которые записывается то, что передаётся им при вызове. Например, имя функции хранится в параметре $0 , первый переданный ей аргумент — в $1 , второй — в $2 , и так далее. Количество переданных функции аргументов можно узнать, обратившись к переменной $# . Если вы знакомы с третьей частью этого цикла материалов, вы не можете не заметить, что всё это очень похоже на то, как скрипты обрабатывают переданные им параметры командной строки.
Аргументы передают функции, записывая их после её имени:
Вот пример, в котором функция вызывается с аргументами и занимается их обработкой:
Вызов функции с аргументами
Функция addnum проверяет число переданных ей при вызове из скрипта аргументов. Если их нет, или их больше двух, функция возвращает значение -1. Если параметр всего один, она прибавляет его к нему самому и возвращает результат. Если параметров два, функция складывает их.
Обратите внимание на то, что функция не может напрямую работать с параметрами, которые переданы скрипту при его запуске из командной строки. Например, напишем такой сценарий:
При его запуске, а точнее, при вызове объявленной в нём функции, будет выведено сообщение об ошибке.
Функция не может напрямую использовать параметры, переданные сценарию
Вместо этого, если в функции планируется использовать параметры, переданные скрипту при вызове из командной строки, надо передать их ей при вызове:
Теперь всё работает правильно.
Передача функции параметров, с которыми запущен скрипт
Работа с переменными в функциях
Переменные, которыми мы пользуемся в сценариях, характеризуются областью видимости. Это — те места кода, из которых можно работать с этими переменными. Переменные, объявленные внутри функций, ведут себя не так, как те переменные, с которыми мы уже сталкивались. Они могут быть скрыты от других частей скриптов.
Существуют два вида переменных:
- Глобальные переменные.
- Локальные переменные.
▍Глобальные переменные
Глобальные переменные — это переменные, которые видны из любого места bash-скрипта. Если вы объявили глобальную переменную в основном коде скрипта, к такой переменной можно обратиться из функции.
Почти то же самое справедливо и для глобальных переменных, объявленных в функциях. Обращаться к ним можно и в основном коде скрипта после вызова функций.
По умолчанию все объявленные в скриптах переменные глобальны. Так, к переменным, объявленным за пределами функций, можно без проблем обращаться из функций:
Вот что выведет этот сценарий.
Обращение к глобальной переменной из функции
Когда переменной присваивается новое значение в функции, это новое значение не теряется когда скрипт обращается к ней после завершения работы функции. Именно это можно видеть в предыдущем примере.
Что если такое поведение нас не устраивает? Ответ прост — надо использовать локальные переменные.
▍Локальные переменные
Переменные, которые объявляют и используют внутри функции, могут быть объявлены локальными. Для того, чтобы это сделать, используется ключевое слово local перед именем переменной:
Если за пределами функции есть переменная с таким же именем, это на неё не повлияет. Ключевое слово local позволяет отделить переменные, используемые внутри функции, от остальных переменных. Рассмотрим пример:
Локальная переменная в функции
Здесь, когда мы работаем с переменной $temp внутри функции, это не влияет на значение, назначенное переменной с таким же именем за её пределами.
Передача функциям массивов в качестве аргументов
Попробуем передать функции в качестве аргумента массив. Сразу хочется сказать, что работать такая конструкция будет неправильно:
Неправильный подход к передаче функциям массивов
Как видно из примера, при передаче функции массива, она получит доступ лишь к его первому элементу.
Для того, чтобы эту проблему решить, из массива надо извлечь имеющиеся в нём данные и передать их функции как самостоятельные аргументы. Если надо, внутри функции полученные ей аргументы можно снова собрать в массив:
Сборка массива внутри функции
Как видно из примера, функция собрала массив из переданных ей аргументов.
Рекурсивные функции
Рекурсия — это когда функция сама себя вызывает. Классический пример рекурсии — функция для вычисления факториала. Факториал числа — это произведение всех натуральных чисел от 1 до этого числа. Например, факториал 5 можно найти так:
Если формулу вычисления факториала написать в рекурсивном виде, получится следующее:
Этой формулой можно воспользоваться для того, чтобы написать рекурсивную функцию:
Проверим, верно ли работает этот скрипт.
Как видите, всё работает как надо.
Создание и использование библиотек
Итак, теперь вы знаете, как писать функции и как вызывать их в том же скрипте, где они объявлены. Что если надо использовать функцию, тот блок кода, который она собой представляет, в другом скрипте, не используя копирование и вставку?
Оболочка bash позволяет создавать так называемые библиотеки — файлы, содержащие функции, а затем использовать эти библиотеки в любых скриптах, где они нужны.
Ключ к использованию библиотек — в команде source . Эта команда используется для подключения библиотек к скриптам. В результате функции, объявленные в библиотеке, становятся доступными в скрипте, в противном же случае функции из библиотек не будут доступны в области видимости других скриптов.
У команды source есть псевдоним — оператор «точка». Для того, чтобы подключить файл в скрипте, в скрипт надо добавить конструкцию такого вида:
Предположим, что у нас имеется файл myfuncs , который содержит следующее:
Это — библиотека. Воспользуемся ей в сценарии:
Только что мы использовали библиотечную функцию внутри скрипта. Всё это замечательно, но что если мы хотим вызвать функцию, объявленную в библиотеке, из командной строки?
Вызов bash-функций из командной строки
Если вы освоили предыдущую часть из этой серии, вы, вероятно, уже догадываетесь, что функцию из библиотеки можно подключить в файле . bashrc , используя команду source . Как результат, вызывать функцию можно будет прямо из командной строки.
Отредактируйте .bashrc , добавив в него такую строку (путь к файлу библиотеки в вашей системе, естественно, будет другим):
Теперь функцию можно вызывать прямо из командной строки:
Вызов функции из командной строки
Ещё приятнее то, что такая вот библиотека оказывается доступной всем дочерним процессам оболочки, то есть — ей можно пользоваться в bash-скриптах, не заботясь о подключении к ним этой библиотеки.
Тут стоит отметить, что для того, чтобы вышеприведённый пример заработал, может понадобиться выйти из системы, а потом войти снова. Кроме того, обратите внимание на то, что если имя функции из библиотеки совпадёт с именем какой-нибудь стандартной команды, вместо этой команды будет вызываться функция. Поэтому внимательно относитесь к именам функций.
Итоги
Функции в bash-скриптах позволяют оформлять блоки кода и вызывать их в скриптах. А наиболее часто используемые функции стоит выделить в библиотеки, которые можно подключать к скриптам, используя оператор source . Если же среди ваших функций найдутся такие, без которых вы прямо таки жить не можете — библиотеки с ними можно подключить в файле .bashrc . Это позволит удобно пользоваться ими в командной строке или в других скриптах. Главное — чтобы имена ваших функций не совпадали с именами встроенных команд.
На сегодня это всё. В следующий раз поговорим об утилите sed — мощном средстве обработки строк.
Уважаемые читатели! А вы пользуетесь функциями собственной разработки для решения повседневных задач?
Источник