جعل xargs تنفيذ الأمر مرة واحدة لكل سطر الإدخال

StackOverflow https://stackoverflow.com/questions/199266

  •  11-07-2019
  •  | 
  •  

سؤال

كيف يمكنني جعل xargs تنفيذ الأمر بالضبط مرة واحدة في كل خط من المدخلات ؟ هذا هو السلوك الافتراضي هو قطعة خطوط و تنفيذ الأمر مرة واحدة ، ويمر خطوط متعددة إلى كل حالة.

من http://en.wikipedia.org/wiki/Xargs:

تجد /path من نوع f-print0 | xargs -0 rm

في هذا المثال تجد يغذي المدخلات من xargs مع قائمة طويلة من أسماء الملفات.xargs ثم تنقسم هذه القائمة إلى sublists ويدعو rm مرة واحدة لكل sublist.هذا هو أكثر كفاءة من هذا وظيفيا الإصدار:

تجد /path من نوع f-exec rm '{}' \;

وأنا أعلم أن تجد لديه "exec" العلم.أنا أقتبس فقط مثال توضيحي من مورد آخر.

هل كانت مفيدة؟

المحلول

وفيما يلي تنجح إلا إذا لم يكن لديك مسافات في الإدخال:

xargs -L 1
xargs --max-lines=1 # synonym for the -L option

من الصفحة رجل:

-L max-lines
          Use at most max-lines nonblank input lines per command line.
          Trailing blanks cause an input line to be logically continued  on
          the next input line.  Implies -x.

نصائح أخرى

يبدو لي كل القائمة إجابات على هذه الصفحة خاطئة ، بما في ذلك وضع علامة الصحيح.هذا ينبع من حقيقة أن المسألة غامضة الصياغة.

موجز: إذا كنت ترغب في تنفيذ الأمر "مرة واحدة في كل خط من مدخل معين،" ويمر خط كامل (بدون السطر) إلى الأمر باعتباره واحد حجة ، ثم وهذا هو أفضل UNIX متوافق مع طريقة للقيام بذلك:

... | tr '\n' '\0' | xargs -0 -n1 ...

جنو xargs قد أو قد لا يكون الملحقات المفيدة التي تسمح لك أن تفعل بعيدا مع tr, لكنهم لا تتوفر على OS X وغيرها من أنظمة UNIX.

الآن لفترة طويلة تفسير...


هناك نوعان من القضايا التي تأخذ في الاعتبار عند استخدام xargs:

  1. كيف تقسيم المدخلات في "حجج";و
  2. كيف العديد من الحجج لتمرير الطفل الأوامر في وقت واحد.

لاختبار xargs سلوك ، نحن بحاجة إلى الأداة التي يظهر كم عدد المرات التي يجري تنفيذها مع كم من الحجج.أنا لا أعرف إذا كان هناك معيار المنفعة للقيام بذلك ، ولكن يمكننا أن قانون ذلك بسهولة تامة في bash:

#!/bin/bash
echo -n "-> "; for a in "$@"; do echo -n "\"$a\" "; done; echo

على افتراض كنت احفظ show في الدليل الحالي وجعلها قابلة للتنفيذ, هنا هو كيف يعمل:

$ ./show one two 'three and four'
-> "one" "two" "three and four" 

الآن, إذا كان السؤال الأصلي هو حقا حول نقطة 2.أعلاه (كما أعتقد أنه بعد قراءته عدة مرات أكثر) و هو أن تقرأ مثل هذا (التغييرات في جريئة):

كيف يمكنني جعل xargs تنفيذ الأمر بالضبط مرة واحدة لكل الحجة من المدخلات ؟ السلوك الافتراضي هو قطعة من الإدخال إلى الحجج وتنفيذ الأوامر كما عدة مرات ممكن, تمرير متعددة الحجج إلى كل حالة.

ثم الجواب -n 1.

دعونا نقارن xargs' السلوك الافتراضي الذي يقسم إدخال جميع أنحاء بيضاء وتطلب الأمر عدة مرات ممكن:

$ echo one two 'three and four' | xargs ./show 
-> "one" "two" "three" "and" "four" 

وسلوكه مع -n 1:

$ echo one two 'three and four' | xargs -n 1 ./show 
-> "one" 
-> "two" 
-> "three" 
-> "and" 
-> "four" 

إذا ، من ناحية أخرى ، الأصلي كان السؤال عن النقطة 1.المدخلات تقسيم يمكن قراءة مثل هذا (كثير من الناس يأتون إلى هنا يبدو أن أعتقد أن هذا هو الحال ، أو يتم الخلط بين المسألتين):

كيف يمكنني جعل xargs تنفيذ الأمر مع بالضبط حجة واحدة لكل خط من المدخلات ؟ السلوك الافتراضي هو قطعة الخطوط حول بيضاء.

ثم الجواب هو أكثر مكرا.

قد يعتقد المرء أن -L 1 يمكن أن تساعد ولكن اتضح أنه لا يغير حجة تحليل.هو فقط ينفذ الأوامر مرة واحدة لكل سطر الإدخال ، مع العديد من الحجج كما كانت هناك على سطر الإدخال:

$ echo $'one\ntwo\nthree and four' | xargs -L 1 ./show 
-> "one" 
-> "two" 
-> "three" "and" "four" 

ليس هذا فقط, ولكن إذا كان خط ينتهي بيضاء ، فإنه يتم إلحاق التالي:

$ echo $'one \ntwo\nthree and four' | xargs -L 1 ./show 
-> "one" "two" 
-> "three" "and" "four" 

بوضوح ، -L لا حول تغيير طريقة xargs يقسم الإدخال إلى الحجج.

الحجة الوحيدة التي تفعل ذلك عبر منصة الأزياء (باستثناء جنو امتداد) ، -0, الذي يقسم الإدخال حول NUL بايت.

ثم انها مجرد مسألة ترجمة أسطر إلى NUL مع مساعدة من tr:

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 ./show 
-> "one " "two" "three and four" 

الآن حجة تحليل يبدو على ما يرام ، بما في ذلك زائدة بيضاء.

أخيرا, إذا كنت الجمع بين هذه التقنية مع -n 1, ، يمكنك الحصول على واحد بالضبط تنفيذ الأمر في سطر الإدخال ، أيا كان الإدخال لديك ، والتي قد تكون طريقة أخرى للنظر في السؤال الأصلي (ربما الأكثر بديهية ، نظرا العنوان):

$ echo $'one \ntwo\nthree and four' | tr '\n' '\0' | xargs -0 -n1 ./show 
-> "one " 
-> "two" 
-> "three and four" 

إذا كنت ترغب في تشغيل الأوامر على كل الخط (أينتيجة) قادمة من find, ثم ماذا تحتاج xargs ؟

محاولة:

find المسار -type f -exec الخاص بك القيادة {} \;

حيث الحرفي {} يتم استبداله من قبل اسم الملف و الحرفي \; مطلوب find أن تعرف أن العرف الأمر ينتهي هناك.

تحرير:

(بعد تعديل السؤال يوضح أن تعرف عن -exec)

من man xargs:

-L ماكس-خطوط
تستخدم في أكثر من ماكس-خطوط nonblank إدخال خطوط في سطر الأوامر.زائدة الفراغات يسبب سطر الإدخال أن يكون منطقيا استمرار التالي سطر الإدخال.يعني -x.

لاحظ أن أسماء الملفات التي تنتهي في الفراغات قد يسبب لك المتاعب إذا كنت تستخدم xargs:

$ mkdir /tmp/bax; cd /tmp/bax
$ touch a\  b c\  c
$ find . -type f -print | xargs -L1 wc -l
0 ./c
0 ./c
0 total
0 ./b
wc: ./a: No such file or directory

حتى إذا كنت لا أهتم -exec الخيار الأفضل استخدام -print0 و -0:

$ find . -type f -print0 | xargs -0L1 wc -l
0 ./c
0 ./c
0 ./b
0 ./a
<اقتباس فقرة>   

وكيف يمكنني أن أجعل xargs تنفيذ الأمر بالضبط مرة واحدة لكل خط من مدخلات معينة؟

وأنا لا تستخدم الإجابة -L 1 لأنه لا يعالج الملفات مع المساحات في تلك التي هي وظيفة أساسية من find -print0.

echo "file with space.txt" | xargs -L 1 ls
ls: file: No such file or directory
ls: space.txt: No such file or directory
ls: with: No such file or directory

والحل الأفضل هو استخدام tr لتحويل أسطر فارغة (\0) حرفا، ومن ثم استخدام الوسيطة xargs -0.

echo "file with space.txt" | tr '\n' '\0' | xargs -0 ls
file with space.txt

إذا كنت تحتاج بعد ذلك للحد من عدد المكالمات التي يمكن استخدام الوسيطة -n 1 لإجراء مكالمة واحدة إلى برنامج لكل المدخلات:

echo "file with space.txt" | tr '\n' '\0' | xargs -0 -n 1 ls

وهذا أيضا يسمح لك لتصفية إخراج العثور <م> قبل تحويل فواصل إلى بالقيم الخالية.

find . -name \*.xml | grep -v /workspace/ | tr '\n' '\0' | xargs -0 tar -cf xml.tar

وثمة بديل آخر ...

find /path -type f | while read ln; do echo "processing $ln"; done
find path -type f | xargs -L1 command 

وهو كل ما تحتاج.

وتعمل هذه الطريقتين أيضا، وسوف تعمل من الأوامر الأخرى التي لا تستخدم تجد!

xargs -I '{}' rm '{}'
xargs -i rm '{}'

والمثال حالة الاستخدام:

find . -name "*.pyc" | xargs -i rm '{}

وسيتم حذف جميع الملفات PYC ضمن هذا الدليل حتى إذا كانت الملفات PYC تحتوي على مسافات.

والأمر التالي سوف تجد كافة الملفات (من نوع و) في /path ثم نسخها باستخدام cp إلى المجلد الحالي. لاحظ استخدام إذا -I % لتحديد شخصية نائب في سطر الأوامر cp بحيث الحجج التي يمكن أن توضع بعد اسم الملف.

وfind /path -type f -print0 | xargs -0 -I % cp % .

واختبار مع xargs (findutils GNU) 4.4.0

ويمكنك الحد من عدد من الخطوط، أو الحجج (إذا كان هناك مسافات بين كل حجة) باستخدام خطوط --max أو وسائط --max الأعلام، على التوالي.

<اقتباس فقرة>
  -L max-lines
         Use at most max-lines nonblank input lines per command line.  Trailing blanks cause an input line to be logically continued on the next  input
         line.  Implies -x.

  --max-lines[=max-lines], -l[max-lines]
         Synonym  for  the -L option.  Unlike -L, the max-lines argument is optional.  If max-args is not specified, it defaults to one.  The -l option
         is deprecated since the POSIX standard specifies -L instead.

  --max-args=max-args, -n max-args
         Use at most max-args arguments per command line.  Fewer than max-args arguments will be used if the size (see  the  -s  option)  is  exceeded,
         unless the -x option is given, in which case xargs will exit.

ويبدو أنني لم يكن لديك ما يكفي من سمعة لإضافة تعليق على الجواب طوبيا في ما سبق ، لذلك أنا وأضاف هذا "الإجابة" لمساعدة أولئك منا الذين يريدون تجربة xargs بنفس الطريقة على أنظمة تشغيل ويندوز.

وهنا هو ملف ويندوز دفعة أن يفعل الشيء نفسه النصي طوبيا ومشفرة بسرعة "إظهار":

@echo off
REM
REM  cool trick of using "set" to echo without new line
REM  (from:  http://www.psteiner.com/2012/05/windows-batch-echo-without-new-line.html)
REM
if "%~1" == "" (
    exit /b
)

<nul set /p=Args:  "%~1"
shift

:start
if not "%~1" == "" (
    <nul set /p=, "%~1"
    shift
    goto start
)
echo.

وDraemon الإجابات يبدو أن الحق مع "-0" حتى مع وجود مساحة في الملف.

وكنت أحاول الأمر xargs ولقد وجدت أن "-0" يعمل تماما مع "لام". يتم التعامل حتى مسافات (إذا تم إنهاء إدخال فارغة). وفيما يلي مثال:

#touch "file with space"
#touch "file1"
#touch "file2"

وفيما يلي سوف تقسيم بلا قيم وتنفيذ الأمر على كل حجة في القائمة:

 #find . -name 'file*' -print0 | xargs -0 -L1
./file with space
./file1
./file2

وهكذا -L1 سيتم تنفيذ حجة على كل حرف منتهية إذا ما استخدمت مع "-0". لمعرفة الفرق المحاولة:

 #find . -name 'file*' -print0 | xargs -0 | xargs -L1
 ./file with space ./file1 ./file2

وحتى هذا سيتم تنفيذ مرة واحدة:

 #find . -name 'file*' -print0  | xargs -0  | xargs -0 -L1
./file with space ./file1 ./file2

والأمر سيتم تنفيذ مرة واحدة باسم "لام" الآن لا تقسيم على بايت فارغة. تحتاج إلى توفير كل من "-0" و "لام" للعمل.

في المثال الخاص بك، وهذه النقطة من الأنابيب إخراج العثور على xargs هي أن السلوك القياسي الخيار العثور على -exec هو تنفيذ الأمر مرة واحدة لكل ملف تم العثور عليها. إذا كنت تستخدم بحث، وتريد سلوكها القياسية، ثم الجواب بسيط - لا تستخدم xargs لتبدأ

وتنفيذ المهمة النمل نظيفة للجميع على كل build.xml على الحالي أو دون المجلد.

find . -name 'build.xml' -exec ant -f {} clean-all \;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top