Как перенаправить список путей, понятных человеку, на другую команду?

Как перенаправить список путей, понятных человеку, на другую команду?

При работе с выводом команд, 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[@]}"

Но все равно остаются две проблемы:

  1. Если locateфайл не найден, du -hc --команда будет запущена без аргументов, что означает, что она выдаст вам информацию об использовании диска в текущем рабочем каталоге.
  2. С другой стороны, если locateбудет найдено много файлов, вы можете достичь предела системного execve()вызова и получитьсписок аргументов слишком длинныйошибка.

Обеих проблем можно избежать, если:

locate -0 '*.doc' | xargs -r0 du -hc --

( -rи -0являясь нестандартными расширениями из реализации GNU, xargslike -hявляется нестандартным расширением из реализации GNU du).

Однако это приводит к новой проблеме: xargsзапуск будет выполняться duнесколько раз, чтобы обойти execve()ограничение, но это означает, что вы получите несколько totalстрок, а также использование диска для файла, жестко связанного несколько раз, может в конечном итоге быть подсчитано несколько раз.

Спасибо -r, команда duне будет запущена, если locateне найдет ни одного файла, но это также означает, что вы не получите ни одной 0 totalстроки.

В последних версиях GNU duэти проблемы можно решить с помощью:

locate -0 '*.doc' | du --files0-from=- -hc

На этот раз список файлов передается через канал, а не через аргументы, поэтому нет ограничений на размер аргументов. Это также означает, что нет необходимости выделять большие объемы памяти для хранения этого списка, и что duможно начать работать с ним, как только locateначнется его вывод.

Связанный контент