Как говорит ridiculous_fish, это, вероятно, связано с обработчиком команды not-found.
Вы можете попробовать добавить это предложение в ваш config.fish
:
function __fish_default_command_not_found_handler --on-event fish_command_not_found
functions --erase __fish_command_not_found_setup
echo "'$argv' not found"
end
Если у вас установлена GNU awk
версии 4 или более поздней, она имеет возможность загружать внешние модули, обеспечивающие функциональность, отсутствующую в стандартном awk или даже в расширенном GNU -awk
. Он поставляется с набором модулей, в том числе с именем filefuncs
. Модуль filefuncs
включает awk
оболочку для системной stat
функции, которую можно использовать для получения информации о файлах (, в том числе о том, существуют они или нет ).
Следующий скрипт awk
загружает модуль filefuncs
, считывает каждую входную строку, проверяет 5-й столбец, чтобы решить, какой путь следует предварительно -ожидать для каждого входного имени файла, и проверяет, существует ли файл. Если это так, он печатает полный путь и имя файла на стандартный вывод. Если это не так, он печатает предупреждающее сообщение в stderr.
Ассоциативный массив paths
(, также известный как «хэш» или «хешированный массив» )и путь по умолчанию, предварительно -ожидающий, — мои лучшие предположения о том, что вы намереваетесь. Отрегулируйте по мере необходимости. Это соответствует данным в предоставленных вами образцах (, даже очевидная ошибка с Media -> /Volumes/Logic ), а не то, что вы сказали в одном из ваших комментариев. Если ваш комментарий точен, то код можно упростить.
#!/usr/bin/awk -f
# this will only work with GNU awk >= version 4.0
@load "filefuncs"
BEGIN {
FS=OFS="|";
paths["default"] = "/Users/spazek/Pictures/Fotos Library.photoslibrary/Masters/";
paths["Logic"] = "/Volumes/Logic/";
paths["Media"] = "/Volumes/Logic/";
paths["macOS"] = "/";
}
{ if ($5 in paths) {
filename = paths[$5] $1;
} else { # $5 not known in paths array, use a default
filename = paths["default"] $1;
}
# try to stat the file. get the return code in variable 'rc' and error
# string (if any) in 'error'.
rc=stat(filename,fstat);
error=ERRNO; # oddly, ERRNO is a string, not a number.
if (rc == -1) { # return code of -1 is "No such file or directory"
# print warning to stdout and skip to next input line
print filename ": " error > "/dev/stderr"
next;
};
# filename exists, do something with filename.
print filename, $2, $3, $4, $5;
}
Сохранить как, например. ./exists.awk
, сделайте его исполняемым с помощьюchmod +x
(так же, как с помощью сценария оболочки ), и запустите его следующим образом:
./exists.awk /Users/spazek/Desktop/filelist1.txt
или направьте sqlite3 прямо в него:
sqlite3 -separator $'|' /Users/spazek/Desktop/xsystx/systphotos.db \
'select RKMaster.imagePath, RKMaster.name, RKMaster.uuid, RKMaster.fileIsReference, ( select RKVolume.name from RKVolume where RKVolume.modelId = RKMaster.volumeId) from RKMaster' \
|./exists.awk
Я не знаю, какая версия awk
в настоящее время поставляется с Mac OS.Я подозреваю, что это, вероятно, либо BSD awk
, либо какая-то древняя версия GNU awk
, существовавшая до того, как Free Software Foundation перешла на использование лицензии GPLv3 (, поэтому Mac застряли на древней bash
v3, а чем текущая bash
версия 4 -, это не потому, что Apple не может обновить bash, а потому, что они не будут . Используйте brew , если вам нужна более поздняя версия GNU bash
или awk
).
В любом случае, если у вас не установлен GNU awk >= v4.0, вы можете сделать то же самое с любой версией perl
.
Следующий скрипт perl
не использует никаких нестандартных -модулей или функций Perl, и даже не требует использования perl
встроенной -в stat()
функции, поскольку в Perl есть операторы. аналогичны тем, что в sh
для проверки существования файла. Здесь мы будем использовать оператор -e
, который проверяет существование файла, как и в sh
:
#!/usr/bin/perl
use strict;
# declare %paths hash
my %paths = (
"default" => "/Users/spazek/Pictures/Fotos Library.photoslibrary/Masters/",
"Media" => "/Volumes/Logic/",
"Logic" => "/Volumes/Logic/",
"macOS" => "/",
);
# main loop, read in each line of input and process it.
while(<>) {
chomp; # strip trailing linefeed from end-of-line
my $filename=''; # declare $filename to belong to this scope
# split input on "|" characters
my ($path,$name,$id,$reference,$diskname) = split /\|/;
if (defined($paths{$diskname})) {
$filename = $paths{$diskname}. $path;
} else { # diskname not known in %paths hash, use a default
$filename = paths{"default"}. $path;
}
if (! -e $filename) {
# print warning to stderr and skip to next input line
warn "$filename: No such file or directory\n";
next;
};
# filename exists, do something with filename.
print join('|', $filename, $id, $reference, $diskname), "\n";
}
Опять же, сохраните его как exists.pl
и сделайте исполняемым с помощью chmod +x
. Выполнить как:
./exists.pl /Users/spazek/Desktop/filelist1.txt
Любой из этих двух сценариев будет в сотни или тысячи раз быстрее, чем сценарий оболочки, использующий while read
или аналогичный цикл.
Я согласен с тем, что gawk4 или perl --или python --являются лучшим решением этой проблемы. Тем не менее, для дальнейшего использования и назидания, можно сделать ваш сценарий оболочки лучше или, по крайней мере, менее плохим.
Во-первых и самое главное, вам не нужно много раз запускатьawk
илиcut
для разделения полей; пока ваши поля разделены одним символом, оболочка read
может сделать это за вас. Я не уверен, почему вы указали разделитель для awk
как [=\|]
, что означает либо знак равенства -, либо vert -правило -, также известное как -, канал, когда ваши данные из команды sqlite3
, которая использует только правило vert -и никогда не использует знак равенства -. Таким образом, вы хотите начать с чего-то вроде:
while IFS='=|' read var1 var2 var3 var4 var5; do... done <filelist1
# change IFS='|' if you don't actually need to split on equal-sign
# could skip the first temp file, if you don't need it for anything else,
# with either a pipeline (any shell):
sqlite3... 'select...' | while IFS.. read...; do... done
# or process substitution (only bash and some others):
while IFS.. read...; do... done < <(sqlite3... 'select...')
Вероятно, лучше добавить опцию -r
к read
; данные вашего примера не содержали обратной косой черты, но если бы фактические данные когда-либо были, они были бы повреждены без -r
. Конвейерный подход немного более переносим, но в целом немного более рискован, потому что он может не работать, когда нужно установить var (s )или внести другие изменения оболочки (s ), например cd
внутри цикл , которые сохраняются после цикла --, но не вы.
Во-вторых, вам не нужно несколько проходов и (так много )промежуточных файлов, если вы объединяете логику:
while IFS.. read -r var1 var2 var3 var4 var5; do
if [ "$var4" == 0 ]; then var1="/Users/spazek/Pictures/Fotos Library.photoslibrary/Masters/$var1"
elif [ "$var5" == "macOS" ]; then var1="/$var1"
else echo var1="/Volumes/$var5/$var1; fi
test -f "$var1" || echo "Name = $var3 \n Path = $var1 \n"
done >~/Desktop/MissingPhotos.txt <filelist1
# or options to avoid filelist1 per above
Наконец, я бы предложил использовать более осмысленные имена переменных, такие как path name id
вместо var1
и т. д., но это имеет значение только для людей, читающих сценарий, таких как вы через несколько месяцев; компьютеру все равно. Вы можете свободно выбирать имена переменных в нижнем регистре для переменных оболочки; по соглашению окружение переменные (т. е. переменные оболочки, которые экспортируются в программы, и дочерние оболочки )пишутся в верхнем регистре, но тогда вы должны быть немного осторожны, чтобы не конфликтовать с некоторыми специальными созданными переменными/окружениями. -в оболочке или стандартизировано для всей системы.