
При работе с выводом команд, locate
которые создают списки путей в «удобочитаемой форме» (т. е. без \
пробелов в начале), как перенаправить их вывод в другую команду?
Вывод $ locate [something]
создает пути с пробелами, что не позволяет другим программам использовать пути в случае, если они содержат пробелы. Например, если бы я
$ du -h `locate *.doc`
это приведет к ошибке для всех файлов и каталогов, содержащих пробелы. (заключение галочек в пробелы не работает)
решение1
Какова конкретная причина, по которой вы используете locate
? Похоже, это делает то, о чем вы просили:
find . -type f -name '*doc' -exec du -h "{}" \;
Тем не менее, если выДействительнохотите использовать такой инструмент, как locate
или find
и передавать его входные данные в качестве параметров другой программе, вы можете воспользоваться разделителями NUL
вывода и ввода, которые предоставляют некоторые инструменты. locate
и find
оба имеют опцию ( locate
's -0
и find
's -print0
), которая позволит вам получить более удобный для программирования вывод, который xargs
предназначен для чтения с помощьюего -0
аргумент:
find . -type f -name '*doc' -print0 | xargs -0 du -h
locate -0 '*doc' | xargs -0 du -h
решение2
Если вам нужно/нужно передать одну и ту же строку нескольким командам, подойдет что-то вроде этого:
#!/usr/bin/env bash
T="${IFS}" # Save off the Internal Field Separator
IFS=$'\n' # Set it to newline.
while read file_line
do
echo "--"
echo "${file_line}"
echo "--"
done <<< $(locate $1)
IFS="${T} # Set it back to the original IFS.
Это хорошая идея, чтобы обернутьлюбойпеременные, которые могут иметь пробелы в "".
решение3
Если оставить подстановки команд ( $(...)
или `...`
архаичную форму) без кавычек, то в оболочках типа Bourne будет вызвана команда split+glob (split только в zsh).
Разделение выполняется по символам специального $IFS
параметра, который по умолчанию содержит пробел, табуляцию и новую строку (и NUL в zsh), что объясняет, почему ваша команда не работает для имен файлов, содержащих пробелы.
Вы можете сделать:
(IFS='
' # split on newline only
set -o noglob # disable glob
du -hc -- $(locate '*.doc'))
Но это все равно не сработает, если имена файлов содержат символы новой строки. Вывод locate
просто не подлежит постобработке.
В большинстве locate
реализаций есть -0
возможность выводить пути к файлам NUL
с разделителями. NUL — единственное байтовое значение, которое не может встречаться в пути к файлу, это означает, что вывод подлежит постобработке. Вам просто нужно разделить по NUL.
В zsh
:
IFS=$'\0'
du -hc -- $(locate -0 '*.doc')
Или, что лучше, использовать явный оператор разделения по NUL:
du -hc -- ${(0)"$(locate -0 '*.doc')"}
В bash
версии 4.4+ это может быть:
readarray -td '' files < <(locate -0 '*.doc')
du -hc -- "${files[@]}"
Но все равно остаются две проблемы:
- Если
locate
файл не найден,du -hc --
команда будет запущена без аргументов, что означает, что она выдаст вам информацию об использовании диска в текущем рабочем каталоге. - С другой стороны, если
locate
будет найдено много файлов, вы можете достичь предела системногоexecve()
вызова и получитьсписок аргументов слишком длинныйошибка.
Обеих проблем можно избежать, если:
locate -0 '*.doc' | xargs -r0 du -hc --
( -r
и -0
являясь нестандартными расширениями из реализации GNU, xargs
like -h
является нестандартным расширением из реализации GNU du
).
Однако это приводит к новой проблеме: xargs
запуск будет выполняться du
несколько раз, чтобы обойти execve()
ограничение, но это означает, что вы получите несколько total
строк, а также использование диска для файла, жестко связанного несколько раз, может в конечном итоге быть подсчитано несколько раз.
Спасибо -r
, команда du
не будет запущена, если locate
не найдет ни одного файла, но это также означает, что вы не получите ни одной 0 total
строки.
В последних версиях GNU du
эти проблемы можно решить с помощью:
locate -0 '*.doc' | du --files0-from=- -hc
На этот раз список файлов передается через канал, а не через аргументы, поэтому нет ограничений на размер аргументов. Это также означает, что нет необходимости выделять большие объемы памяти для хранения этого списка, и что du
можно начать работать с ним, как только locate
начнется его вывод.