Как заставить xargs обрабатывать пробелы и специальные символы из cat?

9

У меня есть, fileкоторый содержит список имен. то есть:

Long Name One (001)
Long Name Two (201)
Long Name Three (123)
...

с пробелами и некоторыми специальными символами. Я хотел сделать каталоги из этих имен, а именно:

cat file | xargs -l1 mkdir

Это делает отдельные каталоги , разделенные пробелами, т.е. Long, Name, One, Two, Three, а Long Name One (001), Long Name Two (201), Long Name Three (123).

Как я могу это сделать?

Majal
источник

Ответы:

13

Используйте -d '\n'с вашей xargsкомандой:

cat file | xargs -d '\n' -l1 mkdir

С manpage:

-d delim
              Input  items  are  terminated  by the specified character.  Quotes and backslash are not special; every
              character in the input is taken literally.  Disables the end-of-file string, which is treated like  any
              other  argument.   This can be used when the input consists of simply newline-separated items, although
              it is almost always better to design your program to use --null where this is possible.  The  specified
              delimiter  may be a single character, a C-style character escape such as \n, or an octal or hexadecimal
              escape code.  Octal and hexadecimal escape codes are understood as for the printf command.    Multibyte
              characters are not supported.

Пример вывода:

$ ls
file

$ cat file
Long Name One (001)
Long Name Two (201)
Long Name Three (123)

$ cat file | xargs -d '\n' -l1 mkdir

$ ls -1
file
Long Name One (001)
Long Name Three (123)
Long Name Two (201)
Pandya
источник
Вам нужен GNU XARGS для -dварианта.
cuonglm
@cuonglm Я думаю, что в основном нашел GNU xargs. Я также проверил 1 , 2 , 3 . да BSD может быть дело
Pandya
6

Если ваш вариант поддержки реализации xargs -0:

tr '\n' '\0' <file | xargs -0 -l1 mkdir

POSIXly:

while IFS= read -r file; do
  mkdir -p -- "$file"
done <file

(Обратите внимание, что использование whileцикла для обработки текста считается плохой практикой в ​​сценарии оболочки)

cuonglm
источник
Обратите внимание, что нет необходимости вызывать по одному mkdirна каталог, mkdirможет принимать более одного аргумента.
Стефан
3

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

-l1не для передачи одной строки ввода в качестве единственного аргумента mkdir, а для вызова одного mkdirвызова для каждой отдельной строки ввода, но со словами в этой строке, которые по-прежнему выделяются в качестве различных аргументов mkdir.

Реализация GNU xargsдобавила -0возможность десятилетия назад принимать входные данные, разделенные NUL. Это наиболее очевидный способ отделить слова, которые в конечном итоге станут аргументами команды, потому что символ NUL оказывается единственным символом, который не может встречаться в аргументе команды или имени файла (выбранный формат списка, в котором по одному файлу в строке не может представлять все возможные имена файлов, так как не допускает новую строку в имени файла).

Это -0было скопировано несколькими другими xargsреализациями, но не всеми.

С тем, что вы можете сделать:

<file tr '\n' '\0' | xargs -0 mkdir -p --

Это будет вызывать mkdirкак можно меньше раз с максимально возможным количеством аргументов.

Но обратите внимание, что если fileон пуст, mkdirон все равно будет запущен, и вы получите синтаксическую ошибку mkdirиз-за отсутствующего аргумента. GNU xargsдобавил -rопцию для того, что было скопировано несколькими другими реализациями.

GNU xargsтакже добавил (позже) -dвозможность указывать произвольные разделители, но я не думаю, что какая-либо другая реализация скопировала его. С GNU xargsлучший способ:

xargs -rd '\n' -a file mkdir -p --

Передавая файл с -a(также расширением GNU) вместо stdin, это означает, что mkdirstdin сохраняется.

POSIXly, вам нужно будет постобработать ввод, чтобы поместить его в ожидаемый формат xargs. Вы можете сделать это, например, с:

<file sed 's/"/"\\""/g; s/^/"/; s/$/"/' | xargs mkdir -p --

Где мы заключаем каждую строку в двойные кавычки и экранируем каждую, "как "\""перед передачей в xargs.

Но остерегайтесь возможных ограничений:

  • ошибка, когда файл пуст уже упомянутый выше
  • может произойти сбой в некоторых реализациях (включая of sed), если содержимое fileне является допустимым текстом в текущей локали. Если fileимена файлов кодируются более чем в одной другой кодировке, или кодировка, отличная от локали, вы можете исправить локаль на C, что должно помочь.
  • некоторые xargsреализации имеют смехотворно низкие ограничения на максимальную длину аргумента (может быть до 255 байт).

Чтобы обойти синтаксическую ошибку при пустой ошибке ввода , вы можете написать:

<file sed 's/"/"\\""/g; s/^/"/; s/$/"/' |
  xargs sh -c '[ "$#" -eq 0 ] || exec mkdir -p -- "$@"' sh
Стефан Шазелас
источник
1

Сделайте так, чтобы имена заканчивались нулем и разделялись там:

cat file | tr '\n' '\0' | xargs -l1 -0 mkdir

trзаменит символ новой строки, который catвыводится \0, а -0флаги в xargsсообщают ему разделить аргументы на \0.

Kira
источник
1

Вы можете сделать это ПОЛОЖИТЕЛЬНО с помощью -Iопции:

xargs -I % mkdir % < file

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/xargs.html

Стивен Пенни
источник
Хотя он будет работать с образцом OP, у вас все еще будут проблемы с ведущими пробелами, одинарными кавычками, двойными кавычками и обратными слешами (и, возможно, длинными строками и последовательностями байтов, не образующими допустимые символы в локали).
Стефан