Да, расширение имени файла при подстановке команд и другие расширения, как правило, нежелательны¹ и не выполняются по умолчанию в zsh, за исключением эмуляции sh/ksh (globsubst
, опция ).
Хотя вы можете использовать ${~$(...)}
, чтобы запросить использование globsusbt для этой конкретной подстановки команд (и, кстати, вам не нужна часть paste
, пробел и новая строка находятся в значении по умолчанию $IFS
), гораздо лучше сделать это с помощью zsh:
ids=($(qstat))
tail -F logs/*${^ids}
Обратите внимание: если какой-либо из этих шаблонов не соответствует какому-либо файлу, выполнение команды будет прервано.
tail -F logs/*${^ids}(N)
(где (N)
активирует nullglob для этих глобусов )избегал бы этого, но запускал бы tail -F
без аргументов, если бы файла вообще не было (см. Почему nullglob не По умолчанию?).
Ты тоже можешь:
logs=(logs/*${^$(qstat)}(N))
(($#logs)) && tail -F $logs
¹ Тот факт, что bash
и другие Bourne -подобные оболочки делают это, можно рассматривать как ошибку. Это одна из причин, по которой вам нужно заключать в кавычки все ваши переменные или почему вам нужно set -o noglob
перед использованием $(...)
без кавычек, когда вам нужна только разделяющая часть этого split+glob. Все более современные оболочки, которые не несут багаж снарядов Борна, таких как rc
, es
или fish
, также не несут этого.
#!/bin/bash
declare -A seen
for name in *.__*.pdf; do
prefix=${name%%.__*.pdf}
if [[ -z ${seen[$prefix]} ]]; then
printf 'keeping "%s"\n' "$name"
seen[$prefix]=1
else
printf 'deleting "%s"\n' "$name"
# rm -f -- "$name"
fi
done
Приведенный выше сценарий извлекает префикс из каждого имени файла, соответствующего шаблону подстановки имени файла *.__*.pdf
в текущем каталоге. Если префикс ранее не встречался, файл сохраняется. В противном случае файл удаляется (команда rm
в настоящее время закомментирована для безопасности ).
Чтобы отслеживать, какие префиксы были просмотрены, они сохраняются как ключи в ассоциативном массиве с именем seen
. Ассоциативные массивы были представлены в bash
выпуске 4.
Поскольку любой файл, соответствующий *.__*.pdf
с тем же префиксом, является «эквивалентным», простое переименование всех этих файлов с одним и тем же именем сведет их к одному файлу.
Это не требует ассоциативного массива и может быть легко выполнено с помощью/bin/sh
:
#!/bin/sh
for name in *.__*.pdf; do
prefix=${name%%.__*.pdf}
printf 'moving "%s" to "%s.__.pdf"\n' "$name" "$prefix"
# mv -f -- "$name" "$prefix.__.pdf"
done
Здесь все файлы с префиксом foo
перемещены в имяfoo.__.pdf
(команда mv
закомментирована для безопасности ).
Вы можете использовать комбинацию find
и awk
:
find./ -mindepth 1 -maxdepth 1 -type f -print0 |
awk 'BEGIN {RS="\x00" ; FS="."}
seen[$2]++ {system("rm '\''"$0"'\''")}'
Это использует NUL в качестве разделителя файлов, поэтому также может обрабатывать такие вещи, как новые строки в именах. Предполагается, что .
используется в качестве разделителя префиксов! Если вам нужен первый (по словарному порядку )каждой партии, вы также можете передать результаты find
черезsort
:
find./ -mindepth 1 -maxdepth 1 -type f -print0 | sort -z |
awk....
Для точного соответствия шаблону .__
вы также можете использовать:
awk 'BEGIN {RS="\x00" ; FS=".__" } seen++[$1] {... }'
Сzsh
:
all=(*.__*.pdf)
typeset -A hash
for f ($all) hash[${f%%.__*}]=$f
keep=($hash)
rm -f -- ${all:|keep}
Среди слов с одинаковым префиксом будет сохранено последнее в лексическом порядке. Вы можете изменить этот порядок с помощью all=(*.__*.pdf(On))
вместо all=(*.__*.pdf)
.
Сzsh
:
declare -A h=()
rm -- *(e:'((h[${REPLY%%.*}]++))':)
К сожалению, это не позволяет установить порядок. Добавление квалификаторов glob o
/ O
здесь только изменит порядок после , исключая первый из каждого, а e
оценивает, следует ли включать/исключать файл в том порядке, в котором файлы найдены (т.е. неупорядоченные, так как *(oN)
вернет их ).
Используя perl
, мы можем открыть дескриптор каталога в текущем каталоге и прочитать все простые файлы, имена которых соответствуют указанному критерию. Имена первых из этих файлов с таким же префиксом выводятся на стандартный вывод, а последующие файлы с этим префиксом удаляются. Префиксы представляют собой ключи хэша%h
perl -le '
opendir my $dh, "."
or die qq(Cannot opendir ".": $!);
-f && /^(.+?)\.__.*\.pdf$/ and
!$h{$1}++ ? print() : unlink()
while readdir $dh;
closedir $dh;
'
Использование команды поиска:
fx() {
set -- "$1" "$tmpdir/${1%%.__*.pdf}"
if [ ! -s "$2" ]; then
echo x > "$2"
shift "$#"
else
rm -f "$1"
fi
return "$#"
}
export -f fx
tmpdir="$(mktemp -d)" \
find. ! -name. -prune -type f \
-name '?*.__*.pdf' \
-exec sh -c 'fx "$1"' find-sh {} \; -print;
Использование python3 вместе с модулем pathlib с той же идеей, что и выше:
python3 -c 'from pathlib import Path
seen = {}
for f in Path(".").glob("?*.__*.pdf"):
if f.is_file():
p = f.name.find(".__")
k = f.name[0:p]
if p > 0:
if k in seen: f.unlink()
else:
print(f.name)
seen[k]=1
'