#!/usr/bin/perl -w use strict; use File::Find (); sub wanted; sub process_file ($@); my $dirfile = shift; # First argument is the filename containing the list # of directories. my $pattern = shift; # Second arg is a perl RE containing the pattern to search # for. Remember to single-quote it on the command line. # Read in the @dirs array from $dirfile # # A NUL-separated file is best, just in case any of the directory names # contained line-feeds. If you're certain that could never happen, a # plain-text LF-separated file would do. # # BTW, you can easily generate a NUL-separated file from the shell with: # printf "%s\0" dir1 dir2 dir3 dir4 $'dir\nwith\n3\nLFs' > dirs.txt my @dirs=(); { local $/="\0"; # delete this line if you want to use a LF-separated file. # In that case, the {... } block around the code from open to # close is no longer needed. It's only there so it's possible # to make a local change to the $/ aka $INPUT_RECORD_SEPARATOR # variable. open(DIRFILE,"<",$dirfile); while(
) { chomp; push @dirs, $_; }; close(DIRFILE); }; File::Find::find({wanted => \&wanted}, @dirs); exit; sub wanted { my ($dev,$ino,$mode,$nlink,$uid,$gid); (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -f _ && process_file($_); } sub process_file ($@) { # This function currently just greps for pattern in the filename passed to # it. As the function name implies, it could be used to process the file # in any way, not just grep it. my $filename = shift; # uncomment the return statement below to skip "binary" files. # (note this is a workable but fairly crude test. Perl's File::MMagic # module can be used to more accurately identify file types, using the # same "magic" file databases as the /usr/bin/file command) # return if -B $filename; open(FILE,"<",$filename); while( ) { print "$filename:$_" if (m/$pattern/o) ; }; close(FILE); } Он использует
perl
и модуль perlFile::Find
, чтобы делать то же самое, что и вашfind... -exec grep
.В этом скрипте нет ничего особенно интересного или особенного , за исключением , что функцию
process_file
можно очень легко модифицировать, чтобы она делала все, что вы хотите, с файлом или с файлом -, например. изменить владельца или разрешения, удалить его, переименовать, вставить или удалить строки или что-то еще, что вы можете захотеть.напр. если вы хотите удалить файлы, которые содержат текст, соответствующий шаблону, вы можете заменить файловую функцию процесса _чем-то вроде этого:
sub process_file ($@) { my $filename = shift; my $found = 0; # uncomment to skip "binary" files: return if -B $filename; open(FILE,"<",$filename); while(
) { if (m/$pattern/o) { $found = 1; last; }; }; close(FILE); unlink $filename if ($found); } Стоит также отметить, что функция
wanted
в этом скрипте в настоящее время ищет только обычные файлы (тест-f
). Функции Perlstat
иlstat
обеспечивают доступ ко всем метаданным файлов, которыеfind
могут использоваться для сопоставления файлов (uid, gid, perms, size, atime, mtime и т. д. ), поэтомуwanted
функция может реплицировать ЛЮБОЙ и все предикаты поиска. подробности см. вperldoc -f stat
иperldoc -f lstat
.Кстати, сценарий был первоначально сгенерирован
find2perl
, а затем существенно изменен для )чтения списка каталогов из файла и b )для выполнения grep в коде perl, а не путем разветвления.grep
и c )добавляют много комментариев. Производительность должна быть почти идентичнаfind... -exec grep
, потому что grep не может открывать файлы или выполнять сопоставление с шаблоном регулярного выражения значительно быстрее, чем это может сделать perl. Это может быть даже быстрее.Кстати,
find2perl
раньше включался в perl,но начиная с perl 5.22 он был удален, и теперь его можно найти на CPAN по адресу find2perl
Думаю, вы хотите что-то сделать в этом направлении:
msgs=("Preparing install..."
"Starting Nginx installation..."
...
)
commands=("sudo apt-get update -y"
"sudo apt-get install nginx -y"
...
)
n=${#commands[@]}
i=0
while [ "$i" -lt "$n" ]; do
pct=$(( i * 100 / n ))
echo XXX
echo $i
echo "${msgs[i]}"
echo XXX
echo "$pct"
eval "${commands[i]}"
i=$((i + 1))
done | whiptail --title "Gauge" --gauge "Please wait..." 10 60 0
Главное здесь — два массива, один для сообщений, другой для команд. Обычно вы хотите использовать полный массив для одной командной строки (см. Как мы можем запустить команду, хранящуюся в переменной? ), но у нас нет 2D-массивов, поэтому их можно хранить в виде строк в eval
.
(Я не исправил это, чтобы получить правильные проценты, уже поздно.)