Cetak semua kecuali tiga kolom pertama


112

Terlalu rumit:

awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things

43
Apakah ada alasan Anda tidak bisa menggunakan begitu saja cut -f3-?
Cascabel

1
@hhh bagus .. Saya suka ide jawaban ringkasan.
Chris Seymour

2
@Jefromi - karena ada masalah buffering baris dengan cut, yang tidak dimiliki awk: stackoverflow.com/questions/14360640/…
sdaau


@Jefromi - juga cuttidak memiliki ekspresi reguler sebelum {}tindakan, dan kemudian jauh lebih bodoh dengan pembatas bidang (jumlah spasi variabel?), Dan Anda harus menentukannya secara manual. Saya pikir OP ingin mendengar tentang beberapa shift Nperintah, yang tidak ada. Yang paling dekat adalah $1="";$2="";(...);print}, tetapi dalam kasus saya ini meninggalkan beberapa spasi utama (mungkin pemisah).
Tomasz Gandor

Jawaban:


50

Solusi yang tidak menambahkan spasi kosong di depan atau di belakang :

awk '{ for(i=4; i<NF; i++) printf "%s",$i OFS; if(NF) printf "%s",$NF; printf ORS}'

### Example ###
$ echo '1 2 3 4 5 6 7' |
  awk '{for(i=4;i<NF;i++)printf"%s",$i OFS;if(NF)printf"%s",$NF;printf ORS}' |
  tr ' ' '-'
4-5-6-7

Sudo_O mengusulkan perbaikan yang elegan dengan menggunakan operator ternerNF?ORS:OFS

$ echo '1 2 3 4 5 6 7' |
  awk '{ for(i=4; i<=NF; i++) printf "%s",$i (i==NF?ORS:OFS) }' |
  tr ' ' '-'
4-5-6-7

EdMorton memberikan solusi untuk menjaga spasi putih asli antar bidang:

$ echo '1   2 3 4   5    6 7' |
  awk '{ sub(/([^ ]+ +){3}/,"") }1' |
  tr ' ' '-'
4---5----6-7

BinaryZebra juga menyediakan dua solusi luar biasa:
(solusi ini bahkan mempertahankan spasi tertinggal dari string asli)

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ for ( i=1; i<=n; i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 ' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."

Solusi yang diberikan oleh larsr di komentar hampir benar:

$ echo '1 2 3 4 5 6 7' | 
  awk '{for (i=3;i<=NF;i++) $(i-2)=$i; NF=NF-2; print $0}' | tr  ' ' '-'
3-4-5-6-7

Ini adalah versi solusi larsr yang diperbaiki dan diparameterisasi :

$ echo '1 2 3 4 5 6 7' | 
  awk '{for(i=n;i<=NF;i++)$(i-(n-1))=$i;NF=NF-(n-1);print $0}' n=4 | tr ' ' '-'
4-5-6-7

Semua jawaban lain sebelum Sep-2013 bagus, tetapi tambahkan spasi tambahan:


Jawaban EdMorton tidak berhasil untuk saya (bash 4.1.2 (1) -release, GNU Awk 3.1.7 atau bash 3.2.25 (1) -release, GNU Awk 3.1.5) tetapi ditemukan di sini dengan cara lain:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch

1
@elysch no, itu tidak akan berfungsi secara umum, itu hanya tampak berfungsi dengan beberapa nilai input tertentu. Lihat komentar yang saya tambahkan di bawah komentar Anda di bawah jawaban saya.
Ed Morton

1
Hai @doyok Jawaban saya adalah yang pertama. Dalam jawaban asli saya, saya menjelaskan mengapa jawaban lain tidak benar (spasi tambahan di depan atau di belakang). Beberapa orang telah mengusulkan peningkatan dalam komentar. Kami telah meminta OP untuk memilih jawaban yang lebih benar, dan dia telah memilih jawaban saya. Setelah beberapa kontributor lain mengedit jawaban saya untuk referensi jawaban di sana (lihat sejarah). Apakah sudah jelas bagi Anda? Apa saran Anda untuk meningkatkan pemahaman jawaban saya? Cheers ;-)
olibre

1
Anda benar sekali dan saya sangat menyesal atas kesalahpahaman saya. Saya membaca cepat untuk menjawab dan tidak memperhatikan jawaban asli Anda (ya, saya membaca terlalu cepat). +1 untuk jawabannya sendiri menggunakan trik bagus untuk mengulang hingga NF-1 dan kemudian mencetak elemen terakhir untuk menghindari spasi ekstra. Dan maaf lagi! (akan menghapus komentar saya dalam satu atau dua hari, untuk mencegah kesalahpahaman dari pembaca di masa mendatang).
fedorqui 'JADI berhenti merugikan'

1
Saya akan menggunakan beberapa jenis tajuk: <jawaban Anda> dan kemudian aturan horizontal diikuti dengan judul besar "perbandingan jawaban lainnya". Jika tidak, pindahkan perbandingan ini ke jawaban lain, karena tampaknya orang cenderung lebih memilih jawaban singkat dalam visi "
berikan

75
awk '{for(i=1;i<4;i++) $i="";print}' file

4
Ini akan meninggalkan ruang depan OFSkarena Anda tidak berurusan dengan, NFyaitu ruang terdepan dalam catatan.
Chris Seymour

70

gunakan potongan

$ cut -f4-13 file

atau jika Anda bersikeras pada awk dan $ 13 adalah kolom terakhir

$ awk '{$1=$2=$3="";print}' file

lain

$ awk '{for(i=4;i<=13;i++)printf "%s ",$i;printf "\n"}' file

14
mungkin lebih baik menggunakan "NF" daripada "13" pada contoh terakhir.
glenn jackman

2
2 skenario terserah OP untuk memutuskan. jika 13 adalah kolom terakhir, menggunakan NF sudah cukup. Jika tidak, menggunakan 13 sudah tepat.
ghostdog74

3
2nd perlu menghapus 3 salinan OFS dari awal $ 0. Yang ketiga akan lebih baik dengan printf "%s ",$i, karena Anda tidak tahu apakah $imungkin mengandung %satau sejenisnya. Tapi itu akan mencetak ruang ekstra di akhir.
dubiousjim

38

Coba ini:

awk '{ $1=""; $2=""; $3=""; print $0 }'

1
Ini bagus karena betapa dinamisnya itu. Anda dapat menambahkan kolom di akhir dan tidak menulis ulang skrip Anda.
MinceMan

1
Ini menunjukkan masalah sebenarnya yang coba Anda tangani, tetapi lakukan yang sebaliknya. Bagaimana dengan mencetak dari bidang ke-100? Catatan untuk menyebutkan Anda tidak berurusan dengan NFsehingga Anda meninggalkan memimpin OFS.
Chris Seymour

24

Cara yang benar untuk melakukannya adalah dengan interval RE karena memungkinkan Anda dengan mudah menyatakan berapa banyak bidang yang akan dilewati, dan mempertahankan jarak antar bidang untuk bidang yang tersisa.

misalnya untuk melewati 3 bidang pertama tanpa mempengaruhi jarak antara bidang yang tersisa mengingat format input yang sepertinya kita bahas dalam pertanyaan ini adalah:

$ echo '1   2 3 4   5    6' |
awk '{sub(/([^ ]+ +){3}/,"")}1'
4   5    6

Jika Anda ingin mengakomodasi spasi utama dan spasi tidak kosong, tetapi sekali lagi dengan FS default, maka:

$ echo '  1   2 3 4   5    6' |
awk '{sub(/[[:space:]]*([^[:space:]]+[[:space:]]+){3}/,"")}1'
4   5    6

Jika Anda memiliki FS yang merupakan RE yang tidak dapat Anda negasikan dalam kumpulan karakter, Anda dapat mengubahnya menjadi satu karakter terlebih dahulu (RS ideal jika itu adalah karakter tunggal karena RS TIDAK DAPAT muncul dalam bidang, jika tidak pertimbangkan LANGGANAN), kemudian terapkan subsitusi interval RE, lalu ubah ke OFS. misalnya jika rantai "." memisahkan bidang:

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,RS);sub("([^"RS"]+["RS"]+){3}","");gsub(RS,OFS)}1'
4 5 6

Tentunya jika OFS adalah karakter tunggal DAN tidak dapat muncul di bidang masukan, Anda dapat menguranginya menjadi:

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,OFS); sub("([^"OFS"]+["OFS"]+){3}","")}1'
4 5 6

Kemudian Anda memiliki masalah yang sama dengan semua solusi berbasis loop yang menetapkan ulang bidang - FS diubah menjadi OFS. Jika itu menjadi masalah, Anda perlu melihat ke fungsi patsplit () GNU awks.


Tidak berfungsi untuk saya (bash 4.1.2 (1) -release, GNU Awk 3.1.7 atau bash 3.2.25 (1) -release, GNU Awk 3.1.5) tetapi ditemukan di sini dengan cara lain:echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch

2
Tidak, itu akan gagal jika $ 1 atau $ 2 berisi string $ 3 yang disetel. Coba, misalnya echo ' That is a test' | awk '{print substr($0, index($0,$3))}'dan Anda akan menemukan bahwa a$ 3 cocok dengan abagian Thatdalam $ 1. Dalam versi yang sangat lama dari gawk seperti yang Anda miliki, Anda perlu mengaktifkan interval RE dengan bendera --re-interval.
Ed Morton

2
Anda benar, tidak menyadarinya. Ngomong-ngomong, sangat hargai komentar Anda. Berkali-kali ingin menggunakan regex dengan "{}" untuk menentukan jumlah elemen dan tidak pernah melihat "--re-interval" pada pria itu. 1 untuk Anda.
elysch

1
1adalah kondisi sebenarnya dan karenanya memanggil tindakan awk default untuk mencetak rekaman saat ini.
Ed Morton

1
saya tidak tahu bagaimana kanonisnya tetapi saya menambahkan jawaban sekarang.
Ed Morton

10

Hampir semua jawaban saat ini menambahkan spasi di depan, spasi tambahan, atau masalah pemisah lainnya. Untuk memilih dari bidang keempat di mana pemisahnya adalah spasi dan pemisah keluaran adalah satu spasi menggunakan awkakan:

awk '{for(i=4;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' file

Untuk parameter bidang awal yang dapat Anda lakukan:

awk '{for(i=n;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' n=4 file

Dan juga kolom penutup:

awk '{for(i=n;i<=m=(m>NF?NF:m);i++)printf "%s",$i (i==m?ORS:OFS)}' n=4 m=10 file

6
awk '{$1=$2=$3="";$0=$0;$1=$1}1'

Memasukkan

1 2 3 4 5 6 7

Keluaran

4 5 6 7

4
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) print $i }'

3
Atau untuk membuatnya di baris yang sama, tetapkan $ 3 ke $ 1, dll. Dan kemudian ubah NF ke jumlah kolom yang tepat. echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
larsr

Hai @larsr. Baris perintah yang Anda usulkan adalah satu-satunya jawaban yang benar. Semua jawaban lainnya menambahkan spasi ekstra (di depan atau di belakang). Silakan kirim baris perintah Anda dalam jawaban baru, saya akan memilihnya ;-)
olibre

1
Hai @sudo_O, saya berbicara dengan @larsr, tentang baris perintah yang dia usulkan dalam komentarnya. Saya menghabiskan sekitar lima menit sebelum mencari tahu quiproco (kesalahpahaman). Saya setuju, jawaban @Vetsin menyisipkan baris baru ( ORS) di antara bidang. Bravo atas inisiatif Anda (saya suka jawaban Anda). Cheers
olibre

3

Cara lain untuk menghindari penggunaan pernyataan cetak:

 $ awk '{$1=$2=$3=""}sub("^"FS"*","")' file

Dalam kondisi awk ketika kondisi true print adalah tindakan default.


Ini memiliki semua masalah yang dimiliki jawaban @lhf .. hanya saja lebih pendek.
Chris Seymour

Ide yang sangat bagus;) Lebih baik dari jawaban saya! (Saya telah memberi suara positif pada jawaban Anda tahun lalu) Cheers
olibre

Seharusnya: awk '{$1=$2=$3=""}sub("^"OFS"+","")' fileseperti OFS apa yang tersisa setelah mengubah konten $ 1, $ 2, dan $ 3.

3

Saya tidak percaya tidak ada yang menawarkan cangkang biasa:

while read -r a b c d; do echo "$d"; done < file

1 untuk solusi serupa ... Tetapi ini mungkin memiliki masalah kinerja jika filebesar (> 10-30KiB). Untuk file besar, awksolusinya bekerja lebih baik.
TrueY

3

Opsi 1 hingga 3 memiliki masalah dengan banyak spasi (tapi sederhana). Itulah alasan untuk mengembangkan opsi 4 dan 5, yang memproses banyak ruang putih tanpa masalah. Tentu saja, jika opsi 4 atau 5 digunakan dengan n=0keduanya akan mempertahankan spasi di depan sebagai n=0cara tidak ada pemisahan.

Pilihan 1

Solusi pemotongan sederhana (bekerja dengan pembatas tunggal):

$ echo '1 2 3 4 5 6 7 8' | cut -d' ' -f4-
4 5 6 7 8

pilihan 2

Memaksa penghitungan ulang awk terkadang menyelesaikan masalah (berfungsi dengan beberapa versi awk) dari spasi tambahan yang ditambahkan:

$ echo '1 2 3 4 5 6 7 8' | awk '{ $1=$2=$3="";$0=$0;} NF=NF'
4 5 6 7 8

Opsi 3

Mencetak setiap bidang yang diformat dengan printfakan memberi lebih banyak kontrol:

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=3 '{ for (i=n+1; i<=NF; i++){printf("%s%s",$i,i==NF?RS:OFS);} }'
4 5 6 7 8

Namun, semua jawaban sebelumnya mengubah semua FS antar bidang menjadi OFS. Mari kita buat beberapa solusi untuk itu.

Pilihan 4

Perulangan dengan sub untuk menghapus bidang dan pembatas lebih portabel, dan tidak memicu perubahan FS menjadi OFS:

$ echo '    1    2  3     4   5   6 7     8  ' |
awk -v n=3 '{ for(i=1;i<=n;i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 '
4   5   6 7     8

CATATAN: The "^ [" FS "] *" untuk menerima masukan dengan spasi di depan.

Pilihan 5

Sangat mungkin untuk membangun solusi yang tidak menambahkan spasi tambahan di depan atau di belakang, dan mempertahankan spasi kosong yang ada menggunakan fungsi gensubdari GNU awk, karena ini:

$ echo '    1    2  3     4   5   6 7     8  ' |
awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }'
4   5   6 7     8 

Ini juga dapat digunakan untuk menukar daftar bidang dengan hitungan n:

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=3 '{ a=gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1);
                b=gensub("^(.*)("a")","\\1",1);
                print "|"a"|","!"b"!";
               }'
|4   5   6 7     8  | !    1    2  3     !

Tentu saja, dalam kasus seperti itu, OFS digunakan untuk memisahkan kedua bagian garis, dan ruang putih di belakang bidang masih dicetak.

Note1: ["FS"]* digunakan untuk memungkinkan spasi di baris input.


Hai BZ Jawaban Anda bagus. Tetapi Opsi 3 tidak bekerja pada string yang dimulai dengan spasi (misalnya " 1 2 3 4 5 6 7 8 "). Opsi 4 bagus tetapi tinggalkan spasi di depan menggunakan string yang dimulai dengan spasi. Apakah menurut Anda jika ini bisa diperbaiki? Anda dapat menggunakan perintah echo " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'untuk memverifikasi spasi di depan / tengah / di belakang ... Cheers;)
olibre

Hai @olib. Bahwa opsi 3 gagal dengan spasi putih adalah alasan untuk mengembangkan opsi 4 dan 5. Opsi 4 hanya menyisakan spasi di depan jika input memilikinya dan n disetel ke 0 (n = 0). Itu saya yakin adalah jawaban yang benar ketika tidak ada pilihan bidang (tidak ada yang memperbaiki IMO). Bersulang.

Baiklah. Terima kasih atas informasi tambahannya :-) Harap perbaiki jawaban Anda dengan memberikan info tambahan ini :-) Salam
olibre

Sempurna :-) Sayang sekali pengguna Anda dinonaktifkan :-(
olibre

1

Cut memiliki tanda --complement yang membuatnya mudah (dan cepat) untuk menghapus kolom. Sintaks yang dihasilkan analog dengan apa yang ingin Anda lakukan - membuat solusi lebih mudah dibaca / dipahami. Pelengkap juga berfungsi untuk kasus di mana Anda ingin menghapus kolom yang tidak bersebelahan.

$ foo='1 2 3 %s 5 6 7'
$ echo "$foo" | cut --complement -d' ' -f1-3
%s 5 6 7
$

Bisakah Anda menjelaskan lebih lanjut jawaban Anda?
Zulu

Apakah hasil edit di atas membantu dalam pemahaman? Intinya adalah menggunakan bendera pelengkap potong. Solusinya harus implementasi yang lebih cepat dan lebih ringkas daripada solusi berbasis AWK atau perl. Juga, kolom sewenang-wenang dapat dipotong.
Michael Kembali

1

Solusi Perl yang tidak menambahkan spasi kosong di depan atau di belakang:

perl -lane 'splice @F,0,3; print join " ",@F' file

@FLarik perl autosplit dimulai pada indeks 0sementara bidang awk dimulai dengan$1


Solusi Perl untuk data yang dipisahkan koma:

perl -F, -lane 'splice @F,0,3; print join ",",@F' file

Solusi Python:

python -c "import sys;[sys.stdout.write(' '.join(line.split()[3:]) + '\n') for line in sys.stdin]" < file


0

Bagi saya, solusi yang paling ringkas dan sesuai untuk permintaan tersebut adalah

$ a='1   2\t \t3     4   5   6 7 \t 8\t '; 
$ echo -e "$a" | awk -v n=3 '{while (i<n) {i++; sub($1 FS"*", "")}; print $0}'

Dan jika Anda memiliki lebih banyak baris untuk diproses seperti misalnya file foo.txt , jangan lupa untuk mengatur ulang i ke 0:

$ awk -v n=3 '{i=0; while (i<n) {i++; sub($1 FS"*", "")}; print $0}' foo.txt

Terima kasih forum Anda.


0

Karena saya kesal dengan jawaban pertama yang sangat disukai tetapi salah, saya menemukan cukup banyak untuk menulis balasan di sana, dan di sini jawaban yang salah ditandai seperti itu, ini sedikit saya. Saya tidak suka solusi yang diusulkan karena saya tidak melihat alasan untuk membuat jawaban menjadi begitu rumit.

Saya memiliki log di mana setelah $ 5 dengan alamat IP bisa lebih banyak teks atau tidak ada teks. Saya membutuhkan semuanya, mulai dari alamat IP hingga akhir baris jika ada sesuatu setelah $ 5. Dalam kasus saya, ini sebenarnya dengan program awk, bukan awk oneliner jadi awk harus menyelesaikan masalah. Ketika saya mencoba untuk menghapus 4 bidang pertama menggunakan jawaban lama yang terlihat bagus dan paling banyak disukai tetapi sepenuhnya salah:

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218 one two three" | awk '{$1=$2=$3=$4=""; printf "[%s]\n", $0}'

itu mengeluarkan tanggapan yang salah dan tidak berguna (saya menambahkan [] untuk menunjukkan):

[    37.244.182.218 one two three]

Sebaliknya, jika kolom memiliki lebar tetap hingga titik potong dan awk diperlukan, jawaban yang benar dan cukup sederhana adalah:

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218 one two three" | awk '{printf "[%s]\n", substr($0,28)}'

yang menghasilkan keluaran yang diinginkan:

[37.244.182.218 one two three]

0

Saya sudah menemukan kemungkinan lain ini, mungkin bisa berguna juga ...

awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file

Catatan: 1. Untuk data tabel dan dari kolom $ 1 sampai $ 14


0

Gunakan potongan:

cut -d <The character between characters> -f <number of first column>,<number of last column> <file name>

misal: Jika sudah file1berisi:car.is.nice.equal.bmw

Jalankan: cut -d . -f1,3 file1 akan mencetakcar.is.nice


Sepertinya solusi Anda mungkin terbelakang. Harap tinjau judul pertanyaan Cetak semua * kecuali * tiga kolom pertama
Stefan Crain

-1

Ini tidak terlalu jauh dari beberapa jawaban sebelumnya, tetapi memecahkan beberapa masalah:

cols.sh:

#!/bin/bash
awk -v s=$1 '{for(i=s; i<=NF;i++) printf "%-5s", $i; print "" }'

Yang sekarang dapat Anda panggil dengan argumen yang akan menjadi kolom awal:

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 3 
3    4    5    6    7    8    9    10   11   12   13   14

Atau:

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 
7    8    9    10   11   12   13   14

Ini 1-indeks; jika Anda lebih suka tidak diindeks, gunakan i=s + 1saja.

Selain itu, jika Anda ingin memiliki argumen untuk indeks awal dan indeks akhir, ubah file menjadi:

#!/bin/bash
awk -v s=$1 -v e=$2 '{for(i=s; i<=e;i++) printf "%-5s", $i; print "" }'

Sebagai contoh:

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 9 
7    8    9

Hasilnya akan %-5sdisejajarkan sebagai kolom dengan lebar 5 karakter; jika ini tidak cukup, tambah jumlahnya, atau gunakan %s(dengan spasi) sebagai gantinya jika Anda tidak peduli tentang perataan.


-1

Solusi berbasis AWK printf yang menghindari% masalah, dan unik karena tidak mengembalikan apa-apa (tidak ada karakter kembali) jika ada kurang dari 4 kolom untuk dicetak:

awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'

Pengujian:

$ x='1 2 3 %s 4 5 6'
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
%s 4 5 6
$ x='1 2 3'
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
$ x='1 2 3 '
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
$
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.