Bir metin dosyasının her satırını bir komuta argüman olarak nasıl iletirim?


42

.txtDosya adını argüman olarak alan, dosya satır satır okuyan ve her satırı bir komuta ileten bir komut dosyası yazmak istiyorum . Örneğin, o zaman çalışır command --option "LINE 1", command --option "LINE 2"vb. Komutun çıktısı başka bir dosyaya yazılır. Bunu nasıl yapacağım? Nereden başlayacağımı bilmiyorum.

Yanıtlar:


26

Kullanım while readdöngüsü:

: > another_file  ## Truncate file.

while IFS= read -r LINE; do
    command --option "$LINE" >> another_file
done < file

Başka bir çıktıyı bloğa göre yönlendirmektir:

while IFS= read -r LINE; do
    command --option "$LINE"
done < file > another_file

Sonuncusu dosyayı açmaktır:

exec 4> another_file

while IFS= read -r LINE; do
    command --option "$LINE" >&4
    echo xyz  ## Another optional command that sends output to stdout.
done < file

Komutların bir giriş okur, komutlar bunu yemez böylece girişi için başka fd kullanmak iyi bir fikir olacağını (varsayarak burada ksh, zshya bashyönelik -u 3kullanımı, <&3yerine portably):

while IFS= read -ru 3 LINE; do
    ...
done 3< file

Son olarak, argümanları kabul etmek için şunları yapabilirsiniz:

#!/bin/bash

FILE=$1
ANOTHER_FILE=$2

exec 4> "$ANOTHER_FILE"

while IFS= read -ru 3 LINE; do
    command --option "$LINE" >&4
done 3< "$FILE"

Hangisi olarak çalıştırabilir:

bash script.sh file another_file

Ekstra fikir İle bash, kullanın readarray:

readarray -t LINES < "$FILE"

for LINE in "${LINES[@]}"; do
    ...
done

Not: IFS=Satır değerlerinin baştaki ve sondaki boşlukların kesilmiş olması sakıncası yoksa ihmal edilebilir.


28

Başka bir seçenek var xargs.

GNU ile xargs:

< file xargs -I{} -d'\n' command --option {} other args

{} Metin satırı için yer tutucudur.

Diğerleri xargsyoktur -d, ancak bazılarının -0NUL ile ayrılmış girişleri vardır. Bunlarla şunları yapabilirsiniz:

< file tr '\n' '\0' | xargs -0 -I{} command --option {} other args

Unix uyumlu sistemlerde ( -IPOSIX'te isteğe bağlıdır ve yalnızca Unix uyumlu sistemler için gereklidir), aşağıdakileri beklenen biçimde satırlara alıntı yapmak için girişi önceden işlemeniz gerekir xargs:

< file sed 's/"/"\\""/g;s/.*/"&"/' |
  xargs -E '' -I{} command --option {} other args

Bununla birlikte, bazı xargsuygulamaların argümanın maksimum boyutu üzerinde çok düşük bir limitin olduğunu unutmayın (örneğin, Solaris'te 255, Unix şartnamesinin izin verdiği minimum).


azaltılabilir<file xargs -L 1 -I{} command --option {} other args
iruvar

@iruvar, hayır, bu alıntıları işleyecek ve bazı boşlukları kaldıracak.
Stéphane Chazelas

7

Soruya tam olarak uymak:

#!/bin/bash

# xargs -n param sets how many lines from the input to send to the command

# Call command once per line
[[ -f $1 ]] && cat $1 | xargs -n1 command --option

# Call command with 2 lines as args, such as an openvpn password file
# [[ -f $1 ]] && cat $1 | xargs -n2 command --option

# Call command with all lines as args
# [[ -f $1 ]] && cat $1 | xargs command --option

1
:-) işe yaradı
BugHunter

3

Bulduğum en iyi cevap:

for i in `cat`; do "$cmd" "$i"; done < $file

DÜZENLE:

... dört yıl sonra ...

Birkaç aşağı oy ve biraz daha deneyimden sonra şimdi aşağıdakileri tavsiye ederim

xargs -l COMMAND < file

3
Bu, komuttaki dosyadaki her kelime için bir kez çağırır . Ayrıca, do "$cmd" "$i";neden olmadığınızı belirlemediğiniz sürece , her zaman kabuk değişkenlerine referans vermelisiniz (içinde olduğu gibi ); Eğer dosya *kendi başına bir kelime olarak içeriyorsa , kodunuz $cmd *çalışır ve bu komut elbette geçerli dizindeki dosyaların bir listesini içerir.
G-Man 'Reeantate Monica' Dedi

1
@ G-Man, haricinde zsh, `cat`zaten *( $igenişletilen bir kısmını tanıtırsa , belirtilmemiş olanı hala bazı joker karakterleri (ikinci bir tur) genişletebilir) genişletirdi `cat`. Her durumda, bu yaklaşım gerçekten de yanlıştır.
Stéphane Chazelas

1
+1. Her satır sadece boşluksuz kullanılan komut için gerekli olan girişi içeriyorsa, bu iyi çalışacaktır.
Subin Sebastian

Bu, her bir kelimeye göre hareket eder, bunun her satırda hareket eden bir değişkeni var mı?
thebunnyrules,

Soru, bir dosya isimlerinin listesini satır satır işlemek oldu.
Steffen Roller,

2
    sed "s/'/'\\\\''/g;s/.*/\$* '&'/" <<\FILE |\
    sh -s -- command echo --option
all of the{&}se li$n\es 'are safely shell
quoted and handed to command as its last argument
following --option, and, here, before that echo
FILE

ÇIKTI

--option all of the{&}se li$n\es 'are safely shell
--option quoted and handed to command as its last argument
--option following --option, and, here, before that echo

-2
ed file.txt
%g/^/s// /
2,$g/^/-,.j
1s/^/command/
wq
chmod 755 file.txt
./file.txt

Bir dosyanın tüm satırlarını al ve bunları tek bir komuta argüman olarak ilet.

command line1 line2 line3 ....

--optionHer çizgiden önce bayrağa ihtiyacınız varsa , ikinci komutu aşağıdaki gibi değiştirin:

%g/^/s// --option /

1
Ed kullanmak için ne -1 ... gerçekten?
user2217522

3
Size indirgemedik, ama muhtemelen bunun nedenleri olan kişinin: (1) Bu soruyu istediği şeyi yapmaz. Bu, komutu komut satırındaki dosyanın tüm içeriğiyle bir kez çağırır; Satır başına bir kere değil . (2) Bu, kabuğa özgü (dosyada olabilecek) karakterleri işlemek için hiçbir şey yapmaz; örneğin ', ", <, >, ;, vb (3) Bu gereksiz bir geçici dosya oluşturur. (4) Bunun gibi şeyler genellikle “burada belgeler” ile yapılır. (5) edEmirleriniz sakar; İlk iki komut indirgenebilir %s/^/ /ve %j.
G-Man 'Reeantate Monica' Dedi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.