В целом, вы, вероятно, должны следовать рекомендации Чарльза Даффи, чтобы использовать более подходящие инструменты для этой задачи. Но я хотел бы go узнать, почему текущий сценарий не работает и как это исправить, в качестве учебного упражнения.
Кроме того, две быстрые рекомендации по проверке и устранению неисправностей сценария оболочки: запустите свои сценарии через shellcheck. net, чтобы указать на распространенные ошибки, а при отладке ставить set -x
перед проблемным разделом (и set +x
после), чтобы оболочка распечатала то, что, по ее мнению, происходит как скрипт выполняется.
Проблема связана с тем, как вы используете переменную file
. Давайте посмотрим, что это делает:
for file in "$(ls | grep .*.c)"
Сначала ls
печатает список файлов в текущем каталоге, по одному на строку. ls
действительно предназначен для интерактивного использования, и его вывод может быть неоднозначным и трудно анализируемым; в сценарии почти всегда есть лучшие способы получения списков имен файлов (и я покажу вам одно из них).
Вывод ls
передается grep .*.c
, что неправильно во многих отношениях. Во-первых, поскольку этот шаблон содержит подстановочный знак ("*
"), оболочка попытается развернуть его в список совпадающих имен файлов. Если каталог содержит какие-либо скрытые (с начальным "."). c файлами, он заменит их списком, и ничего не будет работать вообще правильно. Всегда заключать аргумент шаблона в grep
, чтобы предотвратить это.
Но сам шаблон (".*.c
") также неверен; он ищет любое количество произвольных символов («.*
»), за которым следует один произвольный символ («.
» - это регулярное выражение, поэтому «.
» не обрабатывается буквально), за которым следует "c". И он ищет этот в любом месте строки , поэтому любое имя файла, которое содержит «c» где-то, кроме первой позиции, будет совпадать. Шаблон, который вам нужен, будет выглядеть примерно так: '[.]c$'
(обратите внимание, что я обернул его в одинарные кавычки, поэтому оболочка не будет пытаться обрабатывать $
как ссылку на переменную, как в двойных кавычках).
Тогда есть еще одна проблема, которая является (частью) проблемой, с которой вы на самом деле сталкиваетесь: вывод этого ls | grep
раскрывается в двойных кавычках . Двойные кавычки говорят об этом, чтобы оболочка не делала свое обычное слово-разбиение-и-подстановка-расширение для результата. Обычная (но все же неправильная) вещь, которую нужно здесь сделать, - это исключить двойные кавычки, потому что разделение слов, вероятно, разбивает список имен файлов на отдельные имена, так что вы можете перебирать их один за другим. (Если в имени файла нет забавных символов, в этом случае он может давать странные результаты.) Но с двойными кавычками он не разделяет их, он просто обрабатывает все это как один большой элемент, поэтому ваш l oop запускается один раз с file
установлен в "src1.c\nsrc2.c\nsrc3.c
" (где \n
представляет фактические новые строки).
Это проблема, с которой вы можете столкнуться, анализируя ls
. Не делайте этого, просто используйте подстановочный знак оболочки напрямую:
for file in *.c
Это намного проще, позволяет избежать путаницы в синтаксисе шаблонов регулярных выражений по сравнению с синтаксисом шаблонов шаблонов, неоднозначности в выводе ls
и т. Д. c. Это просто, понятно, и просто работает .
Этого, вероятно, достаточно, чтобы заставить его работать на вас, но есть несколько других вещей, которые вам действительно следует исправить, если вы делаете что-то вроде этого. Во-первых, вы должны заключить в кавычки переменные (т.е. использовать "$file"
вместо $file
). Это еще одна часть ошибки, которую вы получаете; посмотрите на вторую команду awk
:
awk -v nomeprog=$file 'BEGIN{FS="(";printf "the file e %s with the open call:", nameprog}//{ print $2}'
Если для file
установлено значение "src1.c\nsrc2.c\nsrc3.c
", оболочка выполнит на ней свою функцию разделения слов и подстановочных знаков, давая:
awk -v nomeprog=src1.c src2.c src3.c 'BEGIN{FS="(";printf "the file e %s with the open call:", nameprog}//{ print $2}'
awk
, таким образом, установит для своей переменной nomeprog
значение "src1. c", а затем попытается запустить "src2. c" в качестве команды awk (для входных файлов с именем «src3. c» и «НАЧАЛО {FS = ...»). «src2. c», конечно, не является допустимой командой awk, поэтому вы получаете синтаксическую ошибку.
Такая путаница типична для хаоса, который может возникнуть в результате ссылок на переменные без кавычек. Сделайте двойные кавычки для ссылок на переменные.
Другая вещь, которая гораздо менее важна, заключается в том, что у вас есть бесполезное использование cat
. Каждый раз, когда у вас есть шаблон:
cat somefile | somecommand
(и это всего лишь один файл, а не несколько, которые нужно cat
указывать вместе), вы должны просто использовать:
somecommand <somefile
и в некоторых случаях, таких как awk
и grep
, сама команда может принимать входные имена файлов непосредственно в качестве аргументов, поэтому вы можете просто использовать:
somecommand somefile
, так что в вашем случае вместо
cat "$file" | awk '/.*open/{print $0}' | awk -v nomeprog="$file" 'BEGIN{FS="(";printf "the file e %s with the open call:", nameprog}//{ print $2}'
Я бы просто использовал:
awk '/.*open/{print $0}' "$file" | awk -v nomeprog="$file" 'BEGIN{FS="(";printf "the file e %s with the open call:", nameprog}//{ print $2}'
(Хотя, как отметил Чарльз Даффи, даже , что можно упростить довольно много.)