С помощью ed
вы можете использовать регулярное выражение -для поиска вверх , используя ?pattern?
вместо обычного /pattern/
(, которое выполняет поиск сверху текущей позиции ). Так например:
$ printf '%s\n' '?ID?+1,$p' q | ed -s file.txt
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
Без усложнений parallel
, xargs
или передачи путей туда и обратно:
shopt -s nullglob dotglob
for dir in */; do
set -- "$dir"/*
printf '%s:\t%s\n' "${dir%/}" "$#"
done
То есть выполнить итерацию по всем каталогам и подсчитать количество имен, до которых расширяется глобус *
в каждом.
Вышеприведенное относится к bash
, и мы установили параметр оболочки nullglob
, чтобы убедиться, что не соответствующие -шаблоны удаляются, а не сохраняются в нераскрытом виде. Я также устанавливаю параметр оболочки dotglob
, чтобы иметь возможность сопоставлять скрытые имена.
Оболочка zsh
может сделать это, в то же время фильтруя совпадения glob только для каталогов (для цикла )и только, например, для обычных файлов (для тела цикла ). В приведенном ниже коде квалификатор glob (ND/)
делает предыдущий *
совпадающим только с каталогами с тем же эффектом, что и nullglob
и dotglob
, установленными в оболочке bash
, а (ND.)
делает предыдущий *
точно так же соответствуют только обычным файлам.
for dir in *(ND/); do
set -- $dir/*(ND.)
printf '%s:\t%s\n' $dir $#
done
Хотели бы вы сделать это рекурсивно , чтобы получить количество имен в каждом каталоге в иерархии, тогда вы могли бы просто вставить указанное выше вfind
:
find. -type d -exec bash -O nullglob -O dotglob -c '
for dir do
set -- "$dir"/*
printf "%s:\t%s\n" "$dir" "$#"
done' bash {} +
(приведенное выше немного отличается от простого цикла bash
в начале этого ответа, так как он никогда не будет подсчитывать имена в каталогах, доступ к которым осуществляется через символические ссылки )или
find. -type d -exec zsh -c '
for dir do
set -- $dir/*(ND.)
printf "%s:\t%s\n" $dir $#
done' zsh {} +
В GNU Parallel нет проблем с пробелами:
$ mkdir 'a b'
$ touch 'a b/c d'
$ ls | parallel 'echo -n {}" "; ls {}|wc -l'
a b 1
Требуется -0
, если имена содержат \n:
$ mkdir 'a
b'
$ touch 'a
b/c
d'
# fails
$ ls | parallel 'echo -n {}" "; ls {}|wc -l'
$ parallel 'echo -n {}" "; ls {}|wc -l' ::: *
# works
$ printf "%s\0" * | parallel -0 'echo -n {}" "; ls {}|wc -l'
$ parallel -0 'echo -n {}" "; ls {}|wc -l' ::: *
То, что вы видите, вероятно, связано с тем, что вы ls
делаете что-то странное. :Возможно, это псевдоним ls --some-weird-option
. Попробуйте \ls
вместо (или используйте printf... |... -0
или -0... ::: *
, как показано выше ):
\ls | parallel 'echo -n {}" "; ls {}|wc -l'
(PS :Знаете ли вы о--tag
:
parallel --tag 'ls {}|wc -l' ::: *
)