Запишите сценарий оболочки, который переместит все файлы в текущий каталог, содержащий слово “привет” в отдельную папку, названную “привет мировой”

Запишите сценарий оболочки, который переместит все файлы в текущий каталог, содержащий слово hello в отдельную названную папку hello-world.

Текущий каталог содержит файлы a b c d e и f из которых файлов a, c и f содержите слово hello.

Как я могу искать слово hello в файлах текущего каталога и перемещения файлы, удовлетворяющие условие в другой каталог hello-world?

1
задан 1 February 2018 в 19:06

3 ответа

Давайте разломаем это на меньшие задачи. Мы должны

  • создайте каталог hello-world, если это не существует
  • надежно определите файлы, которые содержат текст hello
  • надежно переместите файлы в новый каталог.

Создание каталога, покончили mkdir. Это будет всегда отказываться создавать каталог, который существует (таким образом, отказывающийся перезаписывать такие каталоги), но это также имеет флаг -p который, как упомянуто в man mkdir

-p, --parents
       no error if existing, make parent directories as needed

не потрудился говорить Вам, если каталог, который Вы пытаетесь создать уже, существует.

Таким образом, первая команда нашего сценария могла быть (проверьте, что Вы находитесь в правильном каталоге сначала).

mkdir -p hello-world

Второй шаг определяет файлы, которые мы хотим. Самая очевидная команда для поиска текста в файлах grep. Если мы хотели только имена файлов файлов, которые содержат hello, мы можем использовать -l флаг, который, согласно man grep

-l, --files-with-matches
       Suppress  normal output; instead print the name of each input file
       from which output would normally have been printed.  The scanning
       will stop on the first match.

подавляет нормальный вывод. Но, хотя мы можем выйти сухим из воды для Вашего примера, мы действительно не хотим имен файлов, как произведено, потому что вывод команды является просто текстом, и имена файлов могли бы содержать все виды символов (от скромного пространства до экзотической новой строки), который заставит оболочку видеть что-то другое с подлинного имени файла, к которому Вы хотите сделать что-то, и вести себя способом Вы не хотели. Например, настроив тестовый каталог для Вашего сценария, если я добавляю файл, который имеет пространство на его имя, посмотрите то, что происходит:

$ echo hello > with\ space
$ ls
a  b  c  d  e  f  with space
$ for i in $(grep -l hello *); do echo "$i"; done
a
c
f
with
space

Файл with space рассматривается как два отдельных файла.

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

for var in things; do stuff $var; done

Внутри a for цикл (и где-либо еще также) мы можем использовать test команда, которая иногда похожа [ и также похож [[ сделать условные операторы, и если Вы только хотели проверить, был ли файл пуст или нет, или имело конкретный тип, я буду советовать Вам использовать test команда.

Но Вы хотите найти некоторый конкретный текст, таким образом, мы должны звонить grep, но мы только действительно хотим знать при поиске hello в файле, за которым следуют, таким образом, мы знаем, что затем должны сделать что-то с файлом.

Для создания условного оператора на основе успеха команды мы можем использовать if. if часто используется с test/[/[[, но Вам не нужны они, потому что grep имеет другой полезный флаг:

-q, --quiet, --silent
       Quiet; do not write anything to standard output. Exit immediately
       with zero status if any match is found, even if an error  was detected.

Нуль в Bash означает успех. Таким образом, чтобы сделать, что мы хотим, мы могли записать что-то как

if grep -q hello file; then mv file hello-world; fi

( fi часть if синтаксис команды. Это говорит оболочке об окончании Вашего if)

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

Мы не хотим выполнять ту команду однажды для каждого файла. Это победило бы объект записи сценария, чтобы сделать задание и сохранить нас ввод, так для цикличного выполнения по файлам, которые мы можем использовать for. Постараться не получать ошибку от grep о hello-world каталог, мы можем добавить другой флаг для исключения его.

Вот моя тестовая команда, чтобы сделать это задание и вывод, который я получаю от него в своей тестовой среде:

$ mkdir -p hello-world; for file in *; do if grep -q --exclude-dir=hello-world -- hello "$file"; then echo mv -v -- "$file" hello-world; fi; done
mv -v -- a hello-world
mv -v -- c hello-world
mv -v -- f hello-world
mv -v -- with space hello-world

Этот сценарий не перемещает файлов, из-за echo прежде mv который показывает, какая команда будет выполнена с каждым повторением цикла. Удалить echo после тестирования, если команды выглядят правильными (отмечают, что Вы не можете всегда надежно использовать echo для тестирования, и Вам, возможно, придется представить некоторое временное заключение в кавычки, чтобы сделать так, но оно хорошо работает здесь).

* все нескрытые файлы в текущем каталоге. Более безопасно использовать ./* что означает то же самое, но гарантирует, чтобы все пути запустились с ./ (который является адресом текущего рабочего каталога .), предотвращая имена файлов, запускающиеся с - быть интерпретируемым как опции. Мы имели дело с той возможностью путем добавления -- кому: grep и к mv команда для указания на конец опций. -v mvподробный флаг.

Мы должны заключить переменные в кавычки для подавления расширений оболочки. Если я удаляю кавычки вокруг "$file", мой вывод

mv -v -- a hello-world
mv -v -- c hello-world
mv -v -- f hello-world
grep: with: No such file or directory
grep: space: No such file or directory

Вот сценарий как сценарий:

#!/bin/bash

mkdir -p hello-world
for file in *; do
    if grep -q --exclude-dir=hello-world -- hello "$file"; then
        echo mv -v -- "$file" hello-world
    fi
done

Не забывайте удалять echo когда Вы готовы переместить файлы для реального.

PS, могли бы хорошо быть более эффективные способы сделать это. Моим путем является просто пример.

5
ответ дан 3 December 2019 в 06:52

Это было бы решением после Вашей идеи с grep и xargs:

#!/bin/bash
mkdir hello-world
grep -l hello * | xargs mv -t hello-world
0
ответ дан 3 December 2019 в 06:52

Из названного сценария удара test.sh

#!/bin/sh
IFS=$'\n'
for i in $( grep -l hello --exclude=*.sh --exclude-dir=hello-world * ); do mv $i hello-world/; done;

Из командной строки:

IFS=$'\n' && for i in $( grep -l hello --exclude-dir=hello-world * ); do mv $i hello-world/; done;

Надежды это помогает Вам...

Рассмотрите для создания первого привет мирового каталога.

-1
ответ дан 3 December 2019 в 06:52

Другие вопросы по тегам:

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