Вы правы, это означает 'если $PATH существует - и не является нулевым - тогда добавьте :$PATH'.
Вам нужно проверить, существует ли $PATH, потому что вы не хотите добавлять ведущее (или последующее) двоеточие, если $PATH не определен. Имя каталога нулевой длины (null) в пути, как в :/usr/local/bin:/usr/bin
, или /usr/local/bin:/usr/bin:
, или /usr/local/bin::/usr/bin
, означает поиск в текущем каталоге.
Выдержка из man bash
:
PATH ...
A zero-length (null) directory name in the value of PATH indicates
the current directory. A null directory name may appear as two
adjacent colons, or as an initial or trailing colon.
...
Это, вероятно, не то, что вы хотите сделать.
Следующие две строки делают то же самое:
PATH=":/bin" # search current directory, then /bin
PATH=".:/bin"
Просто перепишите цикл на Perl:
for my $file (glob '*.mrc') {
( my $newname = $file ) =~ s/\..*/.mrc/;
rename $file, $newname or warn "$file: $!";
}
Вы не можете переключать интерпретаторы, но вы можете создать новый процесс оболочки, а затем вернуться к perl:
my $sh_code = <<'END_SH'
for f in *.mrc; do mv -- "$f" "${f%%.*}".mrc ; done
END_SH
system 'bash', '-c', $sh_code
Или вы можете заменить текущий процесс perl оболочкой
exec 'bash', '-c', $sh_code
Но, как отвечает @choroba, perl — это язык общего назначения, и он может справиться практически с любой задачей.
Все можно было сделать на Perl или все в сценарии оболочки. Однако смешивание языков обычно немного запутанно.
Версия сценария оболочки может выглядеть примерно так это (с bash
, например):
#!/bin/bash
dirs=( *.frames )
for dir in "${dirs[@]}"; do
printf 'Working on "%s"\n' "$dir"
cd "$dir"
digitfiles=( RawImage_?.tif )
for file in "${digitfiles[@]}"; do
newfile="RawImage_0${file#RawImage_}"
mv "$file" "$newfile"
done
stackname="../$dir.mrc"
tif2mrc -s *.tif "$stackname"
cd..
done
for f in *.mrc; do
mv -- "$f" "${f%%.*}".mrc
done
Или, немного более идиоматично (теперь с простым sh
, но с использованием find
, который понимает-execdir
):
#!/bin/sh
echo 'Renaming TIFF files'
find *.frames -type f -name 'RawImage_?.tif' \
-execdir sh -c 'mv "$1" "RawImage_0${1#RawImage_}"' sh {} ';'
for d in *.frames; do
printf 'Processing "%s"...\n' "$d"
tif2mrc -s "$d"/*.tif "${d%%.*}.mrc"
done
(оба примера протестированы только в отношении генерации имени файла)
Измените sh -c
на sh -cx
, чтобы получить бит вывода для каждого переименованного файла, или добавьте -print
перед -execdir
.
С помощью -execdir
данная команда оболочки будет выполняться с каталогом найденного файла в качестве рабочего каталога.{}
(и $1
внутри подоболочки )будут базовым именем найденного файла.
Если дляtif2mrc
необходимо запустить внутри каталога файлов TIFF, измените цикл на
for d in *.frames; do
printf 'Processing "%s"...\n' "$d"
(cd "$d" && tif2mrc -s *.tif "../${d%%.*}.mrc" )
done
Обратите внимание, что в Perl использование обратных кавычек для выполнения команды оболочки возвращает вывод этой команды. Вместо этого вы можете использовать
system("tif2mrc -s *.tif $stackname");
, если вас не интересует вывод tif2mrc
.
Кроме того, чтение скрипта или программы, которая меняет каталоги туда и обратно, сбивает с толку. Кроме того, это может привести к нежелательным вещам, если каталог не существует (, chdir("..");
затем поднимет вас на один уровень каталога выше ).
Чтобы правильно это сделать, либо выполните команду со смещенным рабочим каталогом, как в моем последнем примере с оболочкой, либо правильно проверьте код возврата исходного chdir()
в Perl (, это потенциально все равно приведет к коду, который может быть трудно читать и следовать ).
Игнорируя задачу XY и отвечая на вопрос в теме, можно было сделать:
#! /usr/bin/perl
":" || q@<<"=END_OF_PERL"@;
# perl code here
exec "bash", "--", $0, @ARGV;
=END_OF_PERL@
# bash code here
bash
будет игнорировать часть до строки =END_OF_PERL@
, потому что это:
: || something <<"=END_OF_PERL@"
...
=END_OF_PERL@
, в то время как первая строка в perl состоит всего из двух строк(":"
и q@quoted-string@
), объединенных по ИЛИ, поэтому -op.
=END_OF_PERL@
в perl
является началом разделаpod
(документации ), который игнорируется perl
.
Обратите внимание, что если вы хотите передать переменные из perl
в bash
, вы должны экспортировать их в среду (, хотя вы также можете использовать аргументы; здесь мы пересылаем список аргументов, полученных скриптом perl
, скрипту bash
):
$ENV{ENV_VAR} = $perl_var;
Код предполагает, что часть perl
не изменяет текущий рабочий каталог, иначе, если бы $0
был относительным путем, он стал бы недействительным при передаче в bash
. Чтобы обойти это, вы можете указать абсолютный путь к скрипту в начале с помощью:
#! /usr/bin/perl
":" || q@<<"=END_OF_PERL"@;
use Cwd "fast_abs_path";
my $script_path = fast_abs_path $0;
# perl code here
exec "bash", "--", $script_path, @ARGV;
=END_OF_PERL@
# bash code here
Это один из примеров многоязычного сценария, который является допустимым кодом более чем на одном языке. Если вам нравятся эти трюки, вы можете взглянуть на , более экстремальный здесь или codegolf Q&A .
perldoc perlrun
показывает еще один пример полиглота sh
+ perl
, но на этот раз sh
вызывается первым (для систем, которые не поддерживают -удары ).