Поиск в каталоге файлов и вывод результата в текстовый файл

Есть ли какая-нибудь команда для поиска в каталоге файлов и вывода результата в файл с префиксным текстом перед именем найденного файла?

Например, у меня есть каталог с этими файлами:

sound1 sound2 sound3 …

Затем дайте команду для поиска в каталоге и записи результатов в текстовый файл с префиксом перед ним, например

media sound1 media sound2 media sound3 …

Бонусный вопрос

Есть ли способ записать «media1», «media 2» и т. д. вместо «media» в существующий текстовый файл, не удаляя то, что было в этом текстовом файле раньше?

media1 sound1 media2 sound2 media3 sound3 …
5
задан 29 September 2017 в 15:28

10 ответов

Как насчет простого цикла for?

for i in *; do echo media $i >> text_file; done

Объяснения

* - расширяется до каждого файла в текущем каталоге echo media $i - печатает «медиа», и текущее обработанное имя файла >> text_file - перенаправляет вывод echo в файл с именем text_file, добавляя его

Пример

$ ls sound1 sound2 sound3 $ for i in *; do echo media $i >> text_file; done $ cat text_file media sound1 media sound2 media sound3

Бонусный вопрос

k=0; for i in *; do ((k++)); echo media$k $i >> text_file; done

Или для очень большого количества файлов (немного быстрее):

j=text_file; k=0; for i in *; do if [[ "$i" != "$j" ]]; then ((k++)); echo media$k $i; fi; done > "$j"

Пояснения

* - расширяется до каждого файла в текущем каталоге ((k++)) - приращение $k на один

Пример

$ ls sound1 sound2 sound3 $ k=0; for i in *; do ((k++)); echo media$k $i >> text_file; done $ cat text_file media1 sound1 media2 sound2 media3 sound3
3
ответ дан 18 July 2018 в 06:02

Попробуйте этот скрипт:

#!/bin/bash dir=`find /home/username/ -name script_test` ls $dir > test.txt sed -i -e 's/^/media /' test.txt
0
ответ дан 18 July 2018 в 06:02

Это должно помочь:

find /path/to/sound/files -type f -name "sound[0-9]" -printf 'media %f\n' > file.txt

Информация:

sound[0-9]: Ищите файл с именами, которые имеют sound и заканчиваются номером

-printf 'media %f\n': Отформатируйте имя файла с префиксом носителя.

> file.txt: Отправьте его в файл с именем file.txt.

3
ответ дан 18 July 2018 в 06:02

Вы можете использовать команду find следующим образом:

find . ! -name 'sound.txt' -type f -exec sh -c 'echo "media $(basename {}) "' \; > sound.txt

Объяснение:

Первый аргумент - это путь к каталогу, в примере это текущий directory ., но вы можете изменить его на /any/desired/path/. ! -name 'sound.txt' - означает, что элементы с именем sound.txt будут опущены. -type f - означает, что будут найдены только файлы. -exec <command> \; - дать команду find выполнить <command>. {} - выходной аргумент от всей команды до -exec - find . ! -name 'sound.txt' -type f. sh -c 'echo "media $(basename {}) "' - это <command>, который будет выполнен: sh -c - выполнить команду в оболочке /bin/sh; 'echo "media $(basename {}) "' - команда для выполнения: echo "<something>" - выход <something> в STDOUT; media - просто строка; $(<some command>) - обрабатывать результат <some command> как строку; basename {} - печатать только имя файла без его пути, где {} - это переменная, которая содержит полное имя файла, сгенерированное find . ! -name 'sound.txt' -type f. Наконец > перенаправляет STDOUT; sound.txt - это имя файла, в котором STDOUT будет перенаправлен.

Обновление комментариев. В комментариях есть два предложения по упрощению приведенной выше команды:

Первым аргументом является путь к каталогу, в примере это текущий каталог ., но вы можете изменить это /any/desired/path/.

Первый аргумент - это путь к каталогу, в примере это текущий каталог ., но вы можете изменить его на /any/desired/path/.

find . ! -name 'sound.txt' -type f -exec sh -c 'echo media ${0##*/}' {} \; ! -name 'sound.txt' - означает, что элементы с именем sound.txt будут опущены.

Десерт:

$ tree . . ├── sound ├── sound1 ├── sound2 ├── sound3 ├── sound4 ├── sound5 ├── sound99 └── soundd

Обновление из комментариев. Предположим, что у нас есть каталог со следующей структурой:

$ find . ! -name 'sound.txt' -type f -printf 'media %f\n' media sound1 media soundd media sound3 media sound5 media sound2 media sound media sound99 media sound4

Выходы каждой из приведенных выше команд будут идентичны друг другу:

Первым аргументом является путь к каталогу, в примере это текущий каталог ., но вы можете изменить его на /any/desired/path/ .

find . ! -name 'sound.txt' -type f -exec sh -c 'echo media ${0##*/}' {} \;

! -name 'sound.txt' - означает, что элементы с именем sound.txt будут опущены.

find . ! -name 'sound.txt' -type f -printf 'media %f\n' | sort | \ while read -r i; do \ number=$(echo $i | grep -Eo '[0-9]+'); \ if [ -z $number ]; then \ count=$((count+1)); number="\/$count"; \ fi; \ echo $i | sed "s/media/media$number\t/"; \ done Или мы можем использовать этот более простой синтаксис: [f1 0] Пример вывода этой команды будет: $ find . ! -name 'sound.txt' -type f -printf 'media %f\n' | sort | while read -r i; do number=$(echo $i | grep -Eo '[0-9]{1,99}'); [ -z $number ] && count=$((count+1)) && number="\/$count"; echo $i | sed "s/media/media$number\t/"; done media/1 sound media1 sound1 media2 sound2 media3 sound3 media4 sound4 media5 sound5 media99 sound99 media/2 soundd -type f - означает, что будут найдены только файлы.
3
ответ дан 18 July 2018 в 06:02

Сначала распечатайте список файлов (одна запись в строке) в файле (list_of_files)

ls -1 /location/of/the/directory > list_of_files

Затем добавьте фиксированный префикс (media) в каждую строку

sed -i 's/^/media /' list_of_files

Обновление для бонусного вопроса

Чтобы добавить нумерацию, сначала распечатайте список файлов в файле (скажем list_of_files), как и раньше. Затем добавьте номера строк перед каждой строкой

sed -i '=' list_of_files

. Результат будет выглядеть следующим образом:

1 sound1 2 sound2 ...

Затем исправить разрывы строк

sed -i '{N;s/\n/ /}' list_of_files

Теперь будет добавлен фиксированный префикс (media) к каждой строке, как до

sed -i 's/^/media/' list_of_files

. Окончательный выход будет

media1 sound1 media2 sound2 ...
2
ответ дан 18 July 2018 в 06:02

Как насчет простого цикла for?

for i in *; do echo media $i >> text_file; done

Объяснения

* - расширяется до каждого файла в текущем каталоге echo media $i - печатает «медиа», и текущее обработанное имя файла >> text_file - перенаправляет вывод echo в файл с именем text_file, добавляя его

Пример

$ ls sound1 sound2 sound3 $ for i in *; do echo media $i >> text_file; done $ cat text_file media sound1 media sound2 media sound3

Бонусный вопрос

k=0; for i in *; do ((k++)); echo media$k $i >> text_file; done

Или для очень большого количества файлов (немного быстрее):

j=text_file; k=0; for i in *; do if [[ "$i" != "$j" ]]; then ((k++)); echo media$k $i; fi; done > "$j"

Пояснения

* - расширяется до каждого файла в текущем каталоге ((k++)) - приращение $k на один

Пример

$ ls sound1 sound2 sound3 $ k=0; for i in *; do ((k++)); echo media$k $i >> text_file; done $ cat text_file media1 sound1 media2 sound2 media3 sound3
3
ответ дан 24 July 2018 в 18:30
  • 1
    Приятно и просто :) Вы можете изменить его таким образом: for i in *; do echo media${i} $i >> text_file; done, чтобы удовлетворить это требование . – pa4080 29 September 2017 в 14:47
  • 2
    ls -1v | awk '{printf "media% d% s \ n", NR, $ 0}' & gt; text_file работает отлично, если вы делаете это ls -1v | awk '{printf "media% d% s \ n", NR, $ 0}' & gt; & gt; & gt; text_file (добавить символ & quot; & gt; & quot; перед именем файла – joblade 29 September 2017 в 15:44
  • 3
    @joblade Это не работает для меня, но включает в себя text_file на выходе - я добавил свое альтернативное решение. – dessert 29 September 2017 в 15:55
  • 4
    Почему вы открываете и закрываете файл на каждой итерации? Вместо этого вы можете просто сделать for .... done > text_file. – Ruslan 29 September 2017 в 17:40
  • 5
    @Ruslan Вы попробовали это решение? Вы не можете этого сделать, потому что * также будет отображать text_file. Вы могли бы исключить его с помощью [[ "$i" != text_file ]] && …. – dessert 29 September 2017 в 19:36

Попробуйте этот скрипт:

#!/bin/bash dir=`find /home/username/ -name script_test` ls $dir > test.txt sed -i -e 's/^/media /' test.txt
0
ответ дан 24 July 2018 в 18:30
  • 1
    Классная вещь. Работает. Есть ли способ записи «media1», «media 2», и т. д., а не только «носители». в существующий текстовый файл, не удаляя то, что было в этом текстовом файле раньше? – joblade 29 September 2017 в 13:34
  • 2
    Это очень легко, я буду обновлять. теперь я путешествую один раз, я буду обновлять его. – Beginner 29 September 2017 в 14:40
  • 3
    Несмотря на то, что это решение действительно работает, я бы рекомендовал отредактировать ваш ответ, чтобы включить объяснение команд. Это сделало бы его более информативным и лучшим ответом в целом. – Owen Hines 29 September 2017 в 16:24
  • 4
    если вы хотите, чтобы очки взяли его – Beginner 3 October 2017 в 10:48

Это должно помочь:

find /path/to/sound/files -type f -name "sound[0-9]" -printf 'media %f\n' > file.txt

Информация:

sound[0-9]: Ищите файл с именами, которые имеют sound и заканчиваются номером

-printf 'media %f\n': Отформатируйте имя файла с префиксом носителя.

> file.txt: Отправьте его в файл с именем file.txt.

3
ответ дан 24 July 2018 в 18:30
  • 1
    @Dessert спасибо, что человек пытался заставить это работать :-) – George Udosen 29 September 2017 в 14:28
  • 2
    Выражение имени файла должно быть указано: -name "sound[0-9]", в противном случае find возвращает: find: paths must precede expression: sound2. – pa4080 29 September 2017 в 15:07
  • 3
    @ pa4080 работает нормально в моей системе – George Udosen 29 September 2017 в 15:09
  • 4
    Странные вещи случаются иногда – George Udosen 29 September 2017 в 15:11
  • 5
    Привет, Джордж, я исследовал этот вопрос с кавычками. Когда я запускаю команду внутри самого Ubuntu, они не требуются. Но когда я запускаю команду через SSH-соединение PUTTY (из Windows), нужны кавычки. Я также помню эту аналогичную проблему здесь . – pa4080 1 October 2017 в 22:23

Вы можете использовать команду find следующим образом:

find . ! -name 'sound.txt' -type f -exec sh -c 'echo "media $(basename {}) "' \; > sound.txt

Объяснение:

Первый аргумент - это путь к каталогу, в примере это текущий directory ., но вы можете изменить его на /any/desired/path/. ! -name 'sound.txt' - означает, что элементы с именем sound.txt будут опущены. -type f - означает, что будут найдены только файлы. -exec <command> \; - дать команду find выполнить <command>. {} - выходной аргумент от всей команды до -exec - find . ! -name 'sound.txt' -type f. sh -c 'echo "media $(basename {}) "' - это <command>, который будет выполнен: sh -c - выполнить команду в оболочке /bin/sh; 'echo "media $(basename {}) "' - команда для выполнения: echo "<something>" - выход <something> в STDOUT; media - просто строка; $(<some command>) - обрабатывать результат <some command> как строку; basename {} - печатать только имя файла без его пути, где {} - это переменная, которая содержит полное имя файла, сгенерированное find . ! -name 'sound.txt' -type f. Наконец > перенаправляет STDOUT; sound.txt - это имя файла, в котором STDOUT будет перенаправлен.

Обновление комментариев. В комментариях есть два предложения по упрощению приведенной выше команды:

Первым аргументом является путь к каталогу, в примере это текущий каталог ., но вы можете изменить это /any/desired/path/.

Первый аргумент - это путь к каталогу, в примере это текущий каталог ., но вы можете изменить его на /any/desired/path/.

find . ! -name 'sound.txt' -type f -exec sh -c 'echo media ${0##*/}' {} \; ! -name 'sound.txt' - означает, что элементы с именем sound.txt будут опущены.

Десерт:

$ tree . . ├── sound ├── sound1 ├── sound2 ├── sound3 ├── sound4 ├── sound5 ├── sound99 └── soundd

Обновление из комментариев. Предположим, что у нас есть каталог со следующей структурой:

$ find . ! -name 'sound.txt' -type f -printf 'media %f\n' media sound1 media soundd media sound3 media sound5 media sound2 media sound media sound99 media sound4

Выходы каждой из приведенных выше команд будут идентичны друг другу:

Первым аргументом является путь к каталогу, в примере это текущий каталог ., но вы можете изменить его на /any/desired/path/ .

find . ! -name 'sound.txt' -type f -exec sh -c 'echo media ${0##*/}' {} \;

! -name 'sound.txt' - означает, что элементы с именем sound.txt будут опущены.

find . ! -name 'sound.txt' -type f -printf 'media %f\n' | sort | \ while read -r i; do \ number=$(echo $i | grep -Eo '[0-9]+'); \ if [ -z $number ]; then \ count=$((count+1)); number="\/$count"; \ fi; \ echo $i | sed "s/media/media$number\t/"; \ done Или мы можем использовать этот более простой синтаксис: [f1 0] Пример вывода этой команды будет: $ find . ! -name 'sound.txt' -type f -printf 'media %f\n' | sort | while read -r i; do number=$(echo $i | grep -Eo '[0-9]{1,99}'); [ -z $number ] && count=$((count+1)) && number="\/$count"; echo $i | sed "s/media/media$number\t/"; done media/1 sound media1 sound1 media2 sound2 media3 sound3 media4 sound4 media5 sound5 media99 sound99 media/2 soundd -type f - означает, что будут найдены только файлы.
3
ответ дан 24 July 2018 в 18:30
  • 1
    @dessert: Я думаю, что эта часть ! -name 'sound.txt' решает эту проблему. Не так ли? – pa4080 29 September 2017 в 14:42
  • 2
    Вы можете сэкономить basename на -exec sh -c 'echo media ${0##*/}' {} \;. – dessert 29 September 2017 в 14:46
  • 3
    @dessert, спасибо за этот совет. Я пытаюсь выяснить, как добавить счетчик для media # в команде find, любые идеи? – pa4080 29 September 2017 в 14:56
  • 4
    Вы можете заменить -exec sh -c 'echo "media $(basename {}) "' {} \; на -printf 'media %f\n' – steeldriver 29 September 2017 в 15:34
  • 5
    Спасибо, @steeldriver, я пробовал что-то подобное, но безуспешно ... Я уточню ответ. – pa4080 29 September 2017 в 15:41

Сначала распечатайте список файлов (одна запись в строке) в файле (list_of_files)

ls -1 /location/of/the/directory > list_of_files

Затем добавьте фиксированный префикс (media) в каждую строку

sed -i 's/^/media /' list_of_files

Обновление для бонусного вопроса

Чтобы добавить нумерацию, сначала распечатайте список файлов в файле (скажем list_of_files), как и раньше. Затем добавьте номера строк перед каждой строкой

sed -i '=' list_of_files

. Результат будет выглядеть следующим образом:

1 sound1 2 sound2 ...

Затем исправить разрывы строк

sed -i '{N;s/\n/ /}' list_of_files

Теперь будет добавлен фиксированный префикс (media) к каждой строке, как до

sed -i 's/^/media/' list_of_files

. Окончательный выход будет

media1 sound1 media2 sound2 ...
2
ответ дан 24 July 2018 в 18:30
  • 1
    @dessert ls перечисляет для меня одну запись в строке. Но лучше быть в безопасности, я изменил его согласно вашему предложению. Благодарю. – pomsky 29 September 2017 в 14:16
  • 2
    @dessert Уточнение: Я имел в виду, что ls > filename печатает одну запись в строке в filename, но ls в именах списков списков в одной строке. Я думаю, что у нас был небольшой разрыв в коммуникации. – pomsky 29 September 2017 в 14:50
  • 3
    @dessert - это функция многих утилит, позволяющая печатать на tty, но выводить в совместимом режиме при перенаправлении в файл. Например. ls --color=auto, grep --color, современный gcc (≥5.0) по умолчанию печатает цветной вывод на терминал, но прибегает к простому тексту, если stdout не является tty. Аналогично, ls по умолчанию печатает multicolumn в tty, но с одним столбцом в not-a-tty. См. [D0] isatty (3) . – Ruslan 29 September 2017 в 17:45
  • 4
    @Ruslan Спасибо за объяснение! – dessert 29 September 2017 в 19:58

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

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