- Команда cp: правильное копирование папок с файлами в *nix
- Выводы
- Послесловие
- Скопировать имена всех файлов в папке в текстовый файл
- Имена всех файлов в папке в текстовый файл в ОС Windows
- Имена всех файлов в папке в текстовый файл в ОС Linux
- Как скопировать имя файла в терминале линукс?
- Войдите, чтобы написать ответ
- Почему команда curl на windows не подключается к серверу?
- Как получить полное имя файла в одну команду?
- 4 ответа 4
Команда cp: правильное копирование папок с файлами в *nix
В этой статье будут раскрыты некоторые неочевидные вещи связанные с использованием wildcards при копировании, неоднозначное поведение команды cp при копировании, а также способы позволяющие корректно копировать огромное количество файлов без пропусков и вылетов.
Допустим нам нужно скопировать всё из папки /source в папку /target.
Первое, что приходит на ум это:
Сразу исправим эту команду на:
Ключ -a добавит копирование всех аттрибутов, прав и добавит рекурсию. Когда не требуется точное воспроизведение прав достаточно ключа -r .
После копирования мы обнаружим, что скопировались не все файлы — были проигнорированы файлы начинающиеся с точки типа:
.profile
.local
.mc
и тому подобные.
Потому что wildcards обрабатывает shell ( bash в типовом случае). По умолчанию bash проигнорирует все файлы начинающиеся с точек, так как трактует их как скрытые. Чтобы избежать такого поведения нам придётся изменить поведение bash с помощью команды:
Чтобы это изменение поведения сохранилось после перезагрузки, можно сделать файл wildcard.sh c этой командой в папке /etc/profile.d (возможно в вашем дистрибутиве иная папка).
А если в директории-источнике нет файлов, то shell не сможет ничего подставить вместо звёздочки, и также копирование завершится с ошибкой. Против подобной ситуации есть опции failglob и nullglob . Нам потребуется выставить failglob , которая не даст команде выполниться. nullglob не подойдёт, так как она строку с wildcards не нашедшими совпадения преобразует в пустую строку (нулевой длины), что для cp вызовет ошибку.
Однако, если в папке тысячи файлов и больше, то от подхода с использованием wildcards стоит отказаться вовсе. Дело в том, что bash разворачивает wildcards в очень длинную командную строку наподобие:
cp -a /souce/a /source/b /source/c …… /target
На длину командной строки есть ограничение, которое мы можем узнать используя команду:
Получим максимальную длину командной строки в байтах:
…. Maximum length of command we could actually use: 2089314 ….
Итак, давайте будем обходиться вовсе без wildcards.
И тут мы столкнёмся с неоднозначностью поведения cp . Если папки /target не существует, то мы получим то, что нам нужно.
Однако, если папка target существует, то файлы будут скопированы в папку /target/source.
Не всегда мы можем удалить заранее папку /target, так как в ней могут быть нужные нам файлы и наша цель, допустим, дополнить файлы в /target файлами из /source.
Если бы папки источника и приёмника назывались одинаково, например, мы копировали бы из /source в /home/source, то можно было бы использовать команду:
И после копирования файлы в /home/source оказались бы дополненными файлами из /source.
Такая вот логическая задачка: мы можем дополнить файлы в директории-приёмнике, если папки называются одинаково, но если они отличаются, то папка-исходник будет помещена внутрь приёмника. Как скопировать файлы из /source в /target с помощью cp без wildcards?
Чтобы обойти это вредное ограничение мы используем неочевидное решение:
Те кто хорошо знаком с DOS и Linux уже всё поняли: внутри каждой папки есть 2 невидимые папки «.» и «..», являющиеся псевдопапками-ссылками на текущую и вышестоящие директории.
- При копировании cp проверяет существование и пытается создать /target/.
- Такая директория существует и это есть /target
- Файлы из /source скопированы в /target корректно.
Поведение этой команды однозначно. Всё отработает без ошибок вне зависимости от того миллион у вас файлов или их нет вовсе.
Выводы
Если нужно скопировать все файлы из одной папки в другую, не используем wildcards, вместо них лучше использовать cp в сочетании с точкой в конце папки-источника. Это скопирует все файлы, включая скрытые и не завалится при миллионах файлов или полном отсутствии файлов.
Послесловие
vmspike предложил аналогичный по результату вариант команды:
ВНИМАНИЕ: регистр буквы T имеет значение. Если перепутать, то получите полную белиберду: направление копирования поменяется.
Благодарности:
- Компании RUVDS.COM за поддержку и возможность публикации в своем блоге на Хабре.
- За изображение TripletConcept. Картинка очень большая и детальная, можно открыть в отдельном окне.
Скопировать имена всех файлов в папке в текстовый файл
Если вам оказалась полезна или просто понравилась эта статья, тогда не стесняйтесь — поддержите материально автора. Это легко сделать закинув денежек на Яндекс Кошелек № 410011416229354. Или на телефон +7 918-16-26-331.
Даже небольшая сумма может помочь написанию новых статей 🙂
Или поделитесь ссылкой на эту статью со своими друзьями.
Опубликовано: 07.06.2020 Последнее обновление этой статьи: 07.06.2020
В этой инструкция, как скопировать, в текстовый файл, имена всех файлов в папке.
В общем ничего сложного в этом и сделать это можно штатными средствами, которые есть в каждой операционной системе «из коробки». Далее, в этой статье, будут инструкции для двух самых распространенных ОС.
Имена всех файлов в папке в текстовый файл в ОС Windows
В ОС Windows нужно открыть «Командную строку» (файл cmd.exe). И там выполнить команду:
dir /b /a-d > filename.txt
Эта команда расшифровывается так:
- dir — команда, которая показывает содержимое текущего или указанного каталога.
- /b — опция команды, которая показывает, что нужно выводить только имена (без доп. информации).
- /a-d — опция команды, которая показывает, что нужно выводить только файлы, без папок.
- > filename.txt — перенаправление вывода команды в текстовый файл вместо экрана.
Вывод такой команды, в текстовом файле будет выглядеть вот так:
desktop.ini
dvazhdy.rozhdennyj.avi
filename.txt
logo-128.png
logo.jpg
logo.png
ls.txt
Более сложный вариант команды:
dir D:\download /b /a-d > d:\temp\filename.txt
В этом варианте явным образом указаны пути, папки и файла.
Если нужно выбрать файлы из вложенных папок, тогда в команду нужно добавить опцию /s:
dir /b /a-d /s > filename.txt
Если нужно добавлять имена файлов к существующему содержимому файла (без перезаписи файла), тогда условие перенаправления нужно удвоить:
dir /b /a-d >> filename.txt
Имена всех файлов в папке в текстовый файл в ОС Linux
В ОС Linux есть аналогичная команда, которая тоже выполняется в терминале (консоли):
ls -p | grep -v ‘/$’ > filename.txt
Эта команда расшифровывается так:
- ls — команда, которая показывает содержимое текущего или указанного каталога. Но, в отличии от команды Windows, в этой команде нет опции, которая «отсекает» имена папок. Поэтому нужно использовать обходной путь, для получения только имен файлов.
- -p — опция, которая добавляет слэш к именам папок. Это нужно для того, чтобы «отсечь» имена папок.
- | — перенаправление вывода команды ls в команду grep.
- grep — команда, которая обрабатывает входной поток и выбирает из него элементы, по заданным условиям.
- -v ‘/$’ — условие для удаления имен папок.
- > filename.txt — перенаправление вывода команды в текстовый файл вместо экрана.
Таким образом получается следующее:
Команда ls выдает список файлов и папок и перенаправляет этот список в команду grep. Команда grep, удаляет из этого списка имена папок.
Если нужно выбрать файлы из вложенных папок, тогда в команду ls нужно добавить опцию /R:
ls -p -R | grep -v -e ‘/$’ -e ‘^./’ -e ‘^.:’ > filename.txt
Дополнительные OR (ИЛИ) условия команды grep нужны для удаления имен вложенных папок.
Иван Сухов, 2020 г.
Если вам оказалась полезна или просто понравилась эта статья, тогда не стесняйтесь — поддержите материально автора. Это легко сделать закинув денежек на Яндекс Кошелек № 410011416229354. Или на телефон +7 918-16-26-331.
Даже небольшая сумма может помочь написанию новых статей 🙂
Или поделитесь ссылкой на эту статью со своими друзьями.
Copyright digital.workshop 1999 — 2021. Это произведение доступно по лицензии Creative Commons Attribution-NoDerivs 3.0. | Developed by digital.workshop |
Как скопировать имя файла в терминале линукс?
Хочу создать нечто-подобное для копирования имени файла или директории.
Тоже вводишь команду и имя файла, и оно автоматически копируется в буфер обмена.
Заранее благодарен за помощь.
Простой 2 комментария
я понимаю смысл pwd в буфер обмена быстро засовывать, немного.
Но зачем засовывать имя файла в буфер обмена, если вы все равно будете его печатать? Не проще сразу напечатать там где надо? Опишите кейс какой нибудь, пожалуйста
Евгений, мне нужно прописать имя файла в пути в коде, допустим наименование картинки.
Представьте что оно слишком длинное.
alias pbcopy=’xclip -selection clipboard’
Вы случайно не знаете как на линуксе скопировать всю папку целиком с ftp сервера?
ftp> mget копирует множество файлов не не директорию
как-то с wget можно было. не помню(
Thiago Alvarez, нет, я еще до этого не дошел.
Я на сервере или на локалке архивирую папки, потом скачиваю
Gets selected files with expanded wildcards.
-c continue, reget.
-d create directories the same as file names and get the files into them instead of current directory.
-E delete source files after successful transfer
-e delete target file before the transfer
-a use ascii mode (binary is the default)
-P N download N files in parallel
-O specifies base directory or URL where files should be placed
Это из пакета lftp. Вроде как ftp уже устаревший давно считается. Но думаю, там аналогично будет.
Опция -d Вам нужна, вроде бы.
Войдите, чтобы написать ответ
Почему команда curl на windows не подключается к серверу?
Как получить полное имя файла в одну команду?
Как получить полное (с путём относительно / ) имя файла в одну команду? Бывает, работаешь в консоли, и нужно скопировать /полный/путь/к/файлу , например, чтобы в соседней консоли использовать его как аргумент для scp . Приходится вызывать pwd , чтобы скопировать путь к текущей папке, и ls , чтобы скопировать имя файла. Можно ли это сделать в одну команду?
Например, find ‘pwd’/имя_файла (кавычки вокруг pwd — обратные). Или ещё куча вариантов, например, с readlink , как указано в ответе ниже. Количество команд и/или аргументов при этом не имеет вообще никакого значения, ибо есть алиасы.
4 ответа 4
readlink -f покажет /полный/путь/к/файлу.ext , дополнительно «раскрыв» все символические ссылки и заменив их на «канонические» пути. Пример показателен:
$ cd /tmp $ mkdir foo $ touch foo/bar.ext $ ln -s foo/bar.ext baz.ext $ readlink -f foo/bar.ext /tmp/foo/bar.ext $ readlink -f baz.ext /tmp/foo/bar.ext
Здесь /tmp/baz.ext является симлинком на /tmp/foo/bar.ext .
Предложенное решение работает в Linux и FreeBSD, но не работает в Mac OS — у них там своя атмосфера.
Предложу вариант чуть понавороченней:
readlink -m файл | tr -d '\r\n' | xsel -b
- Читаем полный путь
- Сразу же копируем его в буфер обмена, предварительно .
- . вырезав конечные СR/LF (если не хотим, чтобы они добавлялись при вставке)
Для файлов относительно текущего каталога
можно, например, подставлять то, что содержится в переменной окружения $PWD (или в любой другой переменной окружения), даже без «команды», а всего лишь клавиатурным сочетанием. если, конечно, ваша оболочка использует gnu/readline для редактирования командной строки.
например, такая команда привяжет к клавиатурному сочетанию alt+o подстановку значения переменной $PWD (и слэша в конце — для удобства) в текущую позицию курсора:
здесь \eo — это и есть alt+o (а, например, \C-o — это ctrl+o ).
чтобы данная привязка создавалась автоматически в каждой сессии оболочки, можно добавить приведённую команду, например, в стартовый скрипт используемой оболочки — ~/.$rc .
а ещё лучше — добавить строку, которая в примере выше передавалась встроенной команде оболочки bind, прямо в файл ~/.inputrc (конф. файл, используемый gnu/readline-ом):