Bagaimana cara membuat xargs menangani ruang dan karakter khusus dari kucing?

9

Saya punya fileyang berisi daftar nama. yaitu:

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

dengan spasi dan beberapa karakter khusus. Saya ingin membuat direktori dari nama-nama ini, yaitu:

cat file | xargs -l1 mkdir

Itu membuat direktori individu dipisahkan oleh spasi, yaitu Long, Name, One, Two, Three, bukan Long Name One (001), Long Name Two (201), Long Name Three (123).

Bagaimana saya bisa melakukan itu?

Majal
sumber

Jawaban:

13

Gunakan -d '\n'dengan xargsperintah Anda :

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

Dari halaman manual:

-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.

Contoh output:

$ 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
sumber
Anda perlu GNU xargs untuk -dopsi.
cuonglm
@cuonglm Saya pikir sebagian besar ditemukan xargs GNU. Saya juga sudah memeriksa 1 , 2 , 3 . ya BSD mungkin
Pandya
3

xargs mengharapkan format input yang sangat istimewa di mana argumen dibatasi oleh kosong atau baris baru (kadang-kadang bentuk lain dari spasi putih, kadang-kadang tergantung pada lokal saat ini), dan di mana kutipan tunggal, tanda kutip ganda dan backslash dapat digunakan untuk menghindarinya (tetapi dengan cara yang berbeda jalan dari kutipan shell).

-l1bukan untuk meneruskan satu baris input sebagai satu argumen tunggal mkdir, tetapi untuk memanggil satu mkdirpermintaan untuk setiap baris input tetapi dengan kata-kata pada baris itu masih dipisahkan sebagai argumen yang berbeda mkdir.

Implementasi GNU xargsmenambahkan -0opsi beberapa dekade yang lalu untuk menerima input yang dibatasi oleh NUL. Itulah cara yang paling jelas untuk memisahkan kata-kata yang pada akhirnya akan menjadi argumen untuk suatu perintah karena karakter NUL adalah satu-satunya karakter yang tidak dapat muncul dalam argumen perintah atau nama file (format daftar pilihan Anda yang menempatkan satu file per baris tidak dapat mewakili semua nama file yang mungkin karena tidak mengizinkan baris baru dalam nama file).

Itu -0telah disalin oleh beberapa xargsimplementasi lain tetapi tidak semua.

Dengan yang dapat Anda lakukan:

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

Itu akan memanggil mkdirsesering mungkin dengan argumen sebanyak mungkin.

Tetapi perhatikan bahwa jika filekosong, mkdirmasih akan dijalankan dan Anda akan mendapatkan kesalahan sintaksis oleh mkdirkarena argumen yang hilang. GNU xargsmenambahkan -ropsi untuk apa yang telah disalin oleh beberapa implementasi lainnya.

GNU xargsjuga menambahkan (nanti) -dopsi untuk dapat menentukan pembatas yang sewenang-wenang, tapi saya rasa implementasi lainnya tidak menyalinnya. Dengan GNU xargs, cara terbaik adalah dengan:

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

Dengan meneruskan file dengan -a(juga ekstensi GNU) alih-alih stdin, itu berarti mkdirstdin dipertahankan.

POSIXly, Anda harus memposting-proses input untuk memasukkannya ke dalam format yang diharapkan oleh xargs. Anda bisa melakukannya misalnya dengan:

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

Di mana kami menyertakan setiap baris di dalam tanda kutip ganda dan melarikan diri masing "- masing seperti "\""sebelum memberi makan ke xargs.

Namun waspadalah terhadap kemungkinan batasan:

  • kesalahan saat file kosong sudah disebutkan di atas
  • mungkin gagal dengan beberapa implementasi (termasuk dari sed) jika konten filebukan teks yang valid di lokal saat ini. Jika fileberisi nama file yang dikodekan di lebih dari satu charset yang berbeda, atau charset yang berbeda dari yang lokal, Anda dapat memperbaiki lokal ke C yang seharusnya membantu.
  • beberapa xargsimplementasi memiliki batas yang sangat rendah pada panjang maksimum argumen (bisa serendah 255 byte).

Untuk mengatasi kesalahan sintaks saat kesalahan input kosong , Anda dapat menulis:

<file sed 's/"/"\\""/g; s/^/"/; s/$/"/' |
  xargs sh -c '[ "$#" -eq 0 ] || exec mkdir -p -- "$@"' sh
Stéphane Chazelas
sumber
1

Buat nama-nama tersebut nol diakhiri dan pisah di sana:

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

trakan mengganti baris baru yang catdihasilkan dengan \0, dan -0bendera di xargsmengatakan untuk memecah argumen pada \0.

Kira
sumber
1

Anda dapat melakukan ini dengan POSIXLY dengan -Iopsi:

xargs -I % mkdir % < file

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

Steven Penny
sumber
Sementara itu akan bekerja dengan sampel OP, Anda masih akan memiliki masalah dengan memimpin kosong, tanda kutip tunggal, tanda kutip ganda dan garis miring terbalik (dan mungkin garis panjang dan urutan byte tidak membentuk karakter yang valid di lokal).
Stéphane Chazelas