Предпочтительнее использовать awk
. Хороший лайнер. Но просто показать другое решение:
#!/bin/bash
COUNTER=0
IP=
COMPANY=
nmap -sP 192.168.1.* | while read line
do
if [[ "$line" =~ ^Nmap ]]; then
IP=$(echo "$line" | sed -e "s/.*(\(.*\))/\1/")
fi
if [[ "$line" =~ ^MAC ]]; then
COMPANY=$(echo "$line" | sed -e "s/.*(\(.*\))/\1/")
COUNTER=$((COUNTER+1))
echo "${COUNTER}. ${COMPANY} (${IP})"
IP=
COMPANY=
fi
done
Объяснение команд sed:
Первая команда sed извлекает IP-адрес из строк в формате Nmap scan report for macbook.att.net (192.168.1.21)
. Команда sed использует довольно простое регулярное выражение (. Мне также следовало использовать якоря и классы символов, чтобы быть уверенным, что я извлекаю IP-адрес )с помощью группы захвата. Первая часть команды sed (между первой и второй/
)— это строка для сопоставления, .*(\(.*\))
. .*(
соответствует любому (или отсутствию символов ), за которыми следует открывающая скобка. Группа захвата следующая, это \(.*\)
, которая захватывает любое количество символов (в производственной среде, это должно измениться на регулярное выражение, соответствующее формату IP-адреса ). Концом полного регулярного выражения является один )
. Вторая часть команды sed (между второй и третьей/
)— это то, чем заменяется регулярное выражение. В данном случае просто \1
, что указывает на то, что было в первой группе захвата.
Вторая команда sed в основном то же самое, то есть «сопоставьте строку, содержащую набор скобок в конце, замените всю строку тем, что было внутри скобок».
Сложность заключается в том, что когда вы не используете флаг для использования расширенных регулярных выражений, (
и )
являются буквальными. Открывать и закрывать скобки. Их нужно экранировать, \(
и \)
, чтобы указать, что они используются для группировки.
Наконец, опция -e
, которую я использую в команде.В этом случае это необязательно, так как каждая команда sed имеет только один скрипт/регулярное выражение. У меня привычка всегда им пользоваться.
Рекомендуем к прочтению справочные страницы regex(3)
, regex(7)
, которые иногда называют re_format(7)
, и книгу О'Рейли "Освоение регулярных выражений" Джеффри Фридла.
Давайте посмотрим, сработает ли это для вас, если я правильно вас понял:
for i in /path/to/your/dirs/*/info.txt; do
band=$(awk -F'= ' '/^artist/ { print $2 }' "$i")
song=$(awk -F'= ' '/^name/ { print $2 }' "$i")
folder_name="$band - $song"
mv "$(dirname "$i")" "$folder_name"
done
Другой способ сделать это (с использованием утилит GNU ). Если этот тест прошел успешно, удалите echo
, чтобы запустить его.
#!/bin/sh -
for f in */info.txt; do
a="$(grep -Pom1 -- "(?<=^artist = ).*" "$f")"
n="$(grep -Pom1 -- "(?<=^name = ).*" "$f")"
echo mv -T -- "${f%/*}" "$a - $n"
done
Также здесь хорошо -T
. Поведение по умолчанию mv
заключается в переименовании каталога, если цель не существует, и перемещении всего каталога внутрь цели, если цель существует. Таким образом, с -T
в случае любой существующей цели во время этого ничего не будет перемещено.
Я предположил, что все каталоги находятся на одной глубине, и вы должны запускать их с одного уровня выше.
Есть еще один способ, не требующий многократного чтения файла info.txt
:
#!/usr/bin/env bash
## Give a list of target folders in the command line
for dir in "$@"; do
. <(awk -F'=' '$1=="artist" || $1=="name"{
sub(/^ /,"",$2);
print $1"=\""$2"\""
}' "$dir/info.txt")
mv -- "$dir" "$artist - $name"
done
Сохраните это как foo.sh
, сделайте его исполняемым и запустите:
foo.sh path/to/dir1 path/to/dir2... path/to/dirN
Или просто запустите его прямо в терминале:
for dir in path/to/dir1 path/to/dir2... path/to/dirN; do
. <(awk -F'=' '$1=="artist" || $1=="name"{
sub(/^ /,"",$2);
print $1"=\""$2"\""
}' "$dir/info.txt")
mv -- "$dir" "$artist - $name"
done