Это довольно просто с awk
, возможно, выполнимо с sed
.
С awk
у вас будет состояние, которое устанавливается / сбрасывается в каждой строке typedef
и заканчивается в каждой строке правой фигурной скобкой. Подходящий сценарий awk
будет выглядеть как
BEGIN {
state = 0;
typedef="";
fields="";
}
/typedef[ ]+struct/{
state = 1;
typedef=$3;
next;
}
/}.*;/ {
if (state != 0) {
sub("^.*}[ ]*","",$0);
sub(";","",$0);
sub(",$","",fields);
printf "%s %s: %s\n", typedef, $0, fields;
state = 0;
fields = "";
typedef = "";
}
next;
}
(state == 1){
gsub("[ ]+"," ", $0);
gsub(";",",",$0);
fields = fields $0;
next;
}
, где квадратные скобки [
и ]
заключают пробел и табуляцию (чтобы сделать его переносимым). Сценарий состоит из четырех частей:
BEGIN
инициализирует переменные (не обязательно, но некоторые awks делают несколько разные вещи с неинициализированными переменными) typedef
, за которым следуют пробелы и слово struct
. Это ожидает как минимум 3 поля в строке, используя третье в качестве имени typedef. состояние
. $ 0
- текущая строка. Первая замена удаляет все, что находится перед интересующим нас словом, а вторая удаляет точку с запятой, следующую за ним. Третья замена заменяет запятую после переменной fields
, полученной в результате 4-го действия (ниже), на пустую строку.
. Как и в предыдущем действии, здесь используется подстановка для удаления ненужных частей, сначала путем сокращения нескольких пробелов до одного пробела, а затем замены конечной точки с запятой на запятую. Вызовите этот файл foo.awk
и ваши входные данные foo.in
, чтобы использовать awk следующим образом:
awk -f foo.awk
Если вы хотите сопоставить строки, подобные этой:
struct foo {
, а не
typedef struct foo {
, тогда образец можно было бы записать
/^([ ]*typedef)?[ ]+struct[ ]+/{
(опять же, с буквальным пробелом и табуляцией в квадратных скобках). Круглые скобки обозначают группу , а вопросительный знак ?
говорит, что нужно повторить это ноль или более раз. ( {
в строке фактически обозначает начало действия , но я оставил его там, чтобы соответствовать строке в данном скрипте).
Дополнительная литература:
Вариант простой петли оболочки (вbash
):
shopt -s extglob dotglob nullglob
for pathname in ~username/data/!(*.txt); do
! test -d "$pathname" && mv "$pathname" ~username/data/other_files
done
Параметры оболочки, установленные в первой строке, заставят оболочку bash
включить расширенные шаблоны подстановок(!(*.txt)
для соответствия всем именам, не заканчивающимся на .txt
), это позволяет шаблонам подстановок соответствовать скрытым именам, и это делает шаблон расширяться до нуля, если ничего не совпадает.
Тело цикла пропустит все, что является каталогом (или символической ссылкой на каталог ), и переместит все остальное в заданный каталог.
Эквивалентная вещь с find
и GNUmv
(будет перемещать символические ссылки на каталоги, если они есть, и вызывать mv
для максимально возможного количества файлов одновременно, но это единственные различия ):
find ~username/data -maxdepth 1 ! -type d ! -name '*.txt' \
-exec mv -t ~username/data/other_files {} +
Связанные:
Этот код должен переместить все файлы, не заканчивающиеся на «.txt», в вашу целевую папку, однако, если у вас есть файлы с одинаковыми именами по разным путям, это вызовет ошибку.
find /home/username/data ! -name "*.txt" -type f -maxdepth 1 -exec mv {} /home/username/data/other_files/ \;
find /home/username/data -maxdepth 1 -type f ! -name '*.txt' -exec mv {} /home/username/data/other_files/ \;
Следующая строка находит все файлы и скрытые файлы в текущем каталоге, которые не являются *.txt
и не являются путем, и перемещает их в новый путь:
ls -1p | grep -v "^.*\.txt$" | grep -v ".*/$" | xargs mv -vt newpath
Следующее то же самое, но также перемещает скрытые файлы:
ls -1ap | grep -v "^.*\.txt$" | grep -v ".*/$" | xargs mv -vt newpath
Обе командные строки не сканируют каталоги рекурсивно и не перемещают каталоги
Если у вас есть имена файлов, содержащие пробелы, вы можете использовать:
ls -1ap | grep -v "^.*\.txt$" | grep -v ".*/$" | xargs -d'\n' printf "\"%s\"\n" | xargs mv -vt newpath