Смущает вывод с использованием xargs - PullRequest
1 голос
/ 26 августа 2009

У меня есть эти файлы в каталоге: y y1 y2 y3

Выполнение этой команды:
ls y* | xargs -i basename {}|xargs -i sed "s/{}//g"

производит это:
1
2
3

Может кто-нибудь объяснить, почему ?! Я ожидал, что это ничего не даст - запустить sed четыре раза, по одному для каждого файла и каждый раз удалять имя файла. Но на самом деле похоже, что он применяет sed с {}, установленным к первому файлу, в списке y1 y2 y3

Это Солярис 10

Ответы [ 2 ]

2 голосов
/ 26 августа 2009

Когда я пытаюсь это сделать на своем компьютере с Linux, я получаю противоречивые результаты. Иногда 123, иногда (в большинстве случаев) 23, иногда 12. Это тонкое условие буферизации расы между самым правым xargs и любым из sed, которое оно порождает.

Рассечение командной строки:

  • ls y* выведет 4 строки, y, y1, y2 и y3; буферизация не актуальна
  • xargs -i basename {} прочитает их и запустит, в последовательности, basename y, basename y1, basename y2, basename y3; выходные данные, так же как и входные в нашем случае, буферизуются по строкам, так как каждая строка происходит из другого процесса.
  • xargs -i sed "s/{}//g", для каждой строки X, которую он читает (подробнее об этом позже), запускается sed "s/X//g"
  • каждый sed "s/X//g" отфильтровывает каждый X в строках, которые он читает

Где это сложно: две последние команды читают ввод из одного и того же потока. Этот поток создается несколькими различными процессами в последовательности. В зависимости от множества факторов (загрузка системы, планирование) выходные данные могут выходить с очень разными временными диаграммами.

Предположим, они все очень быстрые. Тогда все четыре строки могут быть доступны для правого xargs для чтения в одном блоке. В этом случае не осталось бы ввода для чтения любого из sed, следовательно, вообще не выводит .

С другой стороны, если бы они были очень медленными, для правой стороны xargs могла бы быть доступна только одна строка при первой попытке чтения. Эта строка будет "у". xargs будет порождать первое sed как sed "s/y//g", которое будет использовать все оставшиеся входные данные (y1, y2, y3), полосы y и выходные данные 1, 2, 3 . Вот то же самое объяснение снова с более явным упорядочением.

  1. first basename пишет "y".
  2. вправо xargs читает "y", порождает sed s/y//g. xargs теперь ожидает завершения sed.
  3. секунда basename пишет "y1"; sed читает "y1", пишет "1"
  4. третий basename пишет "y2"; sed читает "y2", пишет "2"
  5. четвертый basename пишет "y3"; sed читает "y3", пишет "3"
  6. осталось xargs готово; sed читает EOF и останавливается
  7. вправо xargs пытается продолжить, читает EOF и останавливается

Не уверен насчет моего 12 случая. Возможно, GNU xargs не дожидается завершения своих потомков, прежде чем прочитает последующие доступные данные, и вырвал строку "y3" из первого sed.

В любом случае вы просто настраиваете конвейер с несколькими одновременными считывателями на одном и том же устройстве записи , что дает в основном недетерминированные результаты. Избегать.

Если бы вы хотели работать с каждым из файлов, этого можно было бы избежать, указав имя файла для использования sed (обратите внимание на окончательный {}):

ls y* | xargs -i basename {} | xargs -i sed "s/{}//g" {}

Если то, что вы хотели, было результатом по кросс-типу продукта (уберите каждое имя файла из каждого файла), вам нужно было бы сделать так, чтобы список файлов создавался столько раз, сколько существует файлов. Плюс один для xargs, если вы все еще использовали это.

Надеюсь, это поможет.

2 голосов
/ 26 августа 2009

Вход для команды xargs -i sed ...:

y
y1
y2
y3

Команда прочитает строку y и выполнит sed s/y//g, которая считывает со стандартного ввода. Стандартный ввод наследуется, поэтому он будет иметь тот же канал, что и стандартный ввод, и, возможно, сможет прочитать оставшиеся данные:

y1
y2
y3

Команда sed s/y//g удалит y из каждой строки:

1
2
3

Однако, если xargs потребляет весь ввод до того, как будет выполнена первая команда sed, то у команды sed не останется ввода для чтения и ничего не будет делать.

...