Dalam skrip bash shell, menulis for for yang berulang di atas nilai string

24

Dalam bash, saya tahu bahwa adalah mungkin untuk menulis forloop di mana beberapa variabel kontrol loop iberulang di atas bilangan bulat yang ditentukan. Misalnya, saya bisa menulis skrip bash shell yang mencetak bilangan bulat antara 1 dan 10:

#!/bin/bash

for i in {1..10}
do
 echo $i
done

Apakah mungkin untuk beralih di atas variabel kontrol loop yang merupakan string, jika saya memberikan daftar string? Misalnya, anggap saya memiliki string fnameyang mewakili nama file. Saya ingin memanggil satu set perintah untuk setiap nama file. Misalnya, saya mungkin ingin mencetak konten fnamemenggunakan perintah seperti ini:

#!/bin/bash

for fname in {"a.txt", "b.txt", "c.txt"}
do
 echo $fname
done

Dengan kata lain, pada iterasi pertama, fnameharus memiliki nilai fname="a.txt", sedangkan pada iterasi kedua, fnameharus memiliki nilai fname="b.txt", dan seterusnya. Sayangnya, tampaknya sintaks di atas tidak sepenuhnya benar. Saya ingin mendapatkan output:

a.txt

b.txt

c.txt

tetapi ketika saya mencoba kode di atas, saya mendapatkan output ini:

{a.txt,

b.txt,

c.txt}

Bisakah Anda membantu saya menentukan sintaks yang benar, sehingga saya bisa mengubah nilai / konten variabel secara berulang fname? Terima kasih atas waktu Anda.

Andrew
sumber
5
Hapus {}, Anda tidak perlu apa pun untuk mengulang daftar (dibatasi-ruang)
Mat
3
@Mat berarti menghapus {} dan yang ,s. Alternatifnya adalah menghapus spasi. Jadi salah satu "a.txt" "b.txt" "c.txt"atau {"a.txt","b.txt","c.txt"}. Tapi saya lebih suka {a..c}.txtsebagai gantinya.
manatwork

Jawaban:

39

Sintaks yang benar adalah sebagai berikut:

#!/bin/bash

for fname in a.txt b.txt c.txt
do
  echo $fname
done
Ali Gangji
sumber
9
Juga, dengan asumsi array nama fnames=( a.txt b.txt c.txt )Anda dapat menggunakan sintaks for f in ${fnames[@]}; do echo $f; done.
1
Benarkah itu for fname in a.txt b.txt c.txtdan for fname in "a.txt" "b.txt" "c.txt"menghasilkan hasil yang identik?
Andrew
Andrew, ya itu benar. Mereka akan menghasilkan hasil yang identik
Ali Gangji
1
Tentu saja Anda harus menggunakan for f in "${fnames[@]}"; do echo $f; done(dengan tanda kutip ${fnames[@]}) jika fnamesnilainya mungkin berisi spasi kosong. Dan Anda harus menggunakannya "$f", terutama jika Anda melakukan sesuatu yang lebih canggih daripada echo(misalnya, catatau cp). (Dan bahkan jika Anda hanya melakukannya echo, Anda harus menggunakannya printfsebagai gantinya.)
Scott
Saya pikir @ user13742 juga harus dicatat dalam jawabannya.
Fallenreaper
1

Menurut saya Anda hanya harus melakukan ...

printf %s.txt\\n a b c
mikeserv
sumber
Saya suka ini meskipun OP kemungkinan memiliki sesuatu untuk dilakukan selain gema sebelum dia selesai.
Penatua Geek
0

Seperti yang dicatat oleh user13742 dalam komentar , kita dapat menggunakan array di bashdan ksh:

#!/usr/bin/env bash

files_list=( "a.txt" "b.txt" "c and space.txt" )

for i in "${files_list[@]}"
do
    echo "$i"
    # do something else here,maybe
done

Dan berfungsi seperti itu:

$ ./iterate_files_array.sh                                                      
a.txt
b.txt
c and space.txt

Namun, beberapa shell seperti dash( /bin/shdi Ubuntu) tidak mendukung array. Dalam kasus seperti itu kita dapat menggunakan struktur dokumen-sini:<<

#!/bin/sh

while IFS= read -r line
do
    echo "$line"
done << EOL
one.txt
two.txt
with space.txt
EOL
Sergiy Kolodyazhnyy
sumber