3

У меня есть структура каталогов с 14 каталогами, содержащими кучу файлов, содержащих данные в формате трех столбцов (разделенных вкладками). Я намеревался использовать find и awk, чтобы извлечь второй столбец из каждого из этих файлов и вывести его с тем же именем файла, но в другой корневой папке. Вот набросок моего каталога.

данные / все -> AA, AB, AC, AD ... (A * - это папки, содержащие файлы с данными, сохраненными в формате с тремя столбцами, например, AA100.txt, AA101.txt ...)

я хочу, чтобы измененные (с одним столбцом) файлы с тем же именем, но все в новом корневом каталоге data/pos (в отличие от data/all/) -> AA, AB, AC, AD ... (снова каждый из которых содержит A * 100.txt, A * 101 ...)

Я попытался использовать find -exec и дать ему команду awk, но у меня проблемы с выводом файла в нужное место.

когда в данных / все /

find * -type f -exec awk '{print $ 2}' '{}'> ../pos/'{}' \;

Однако {} как подстановочный знак для входного файла, кажется, не работает при выводе файла?

Что я делаю неправильно? (Я на сервере Ubuntu, кстати)

3 ответа3

5

Что я делаю неправильно?

Вы используете перенаправление > ../pos/'{}' как если бы оно было обработано командами find или awk но перенаправления обрабатываются оболочкой. В вашем случае это означает, что вы можете перенаправить только вывод всей find (не вывод awk).

Обратите внимание, что вам обычно не нужно использовать подстановочный знак, такой как * для начального пути find . Это обычный способ find . что вы хотели сделать или есть ли причина find *?

Решения

Здесь мы сохраним гибкость find в отличие от решения Якобо де Вера. Запустите awk в цикле оболочки:

find . -type f -print0 |
  while read -r -d $'\0' x; do
    awk '{print $2}' "$x" > "../pos/$(basename "$x")"
  done

Исходный способ с -exec будет менее эффективным, потому что для каждого файла будет запускаться оболочка в дополнение к awk и многоуровневое экранирование здесь довольно сложно:

find . -type f -exec sh -c 'awk "{print \$2}" "{}" > "../pos/{}"' \;

Также может быть альтернативное решение сделать перенаправление внутри awk .

3

Вы можете попробовать без поиска, если все, что вы хотите, это все файлы. Пока в data/all/ , запустите это:

for file in ./*; do awk '{print$2}' "$file" > "../pos/$(basename $file)"; done

Если вы хотите охватить файлы во всей иерархии в /data/all , вы можете включить опцию globstar если вы используете bash (я считаю, что это будет "просто работать" на zsh), а затем использовать ** чтобы сопоставить все файлы:

shopt -s globstar
for file in ./**; do awk '{print$2}' "$file" > "../pos/$(basename $file)"; done
-1

find /path -exec ls -l {} \; | awk '{print $ 1}'

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .