Parallel и ls с пробелами

С помощью 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
1
21.11.2021, 13:20
2 ответа

Без усложнений 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 {} +
2
21.11.2021, 18:02

В 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' ::: *

)

2
28.11.2021, 11:38

Теги

Похожие вопросы