Redirect output dari semua perintah ke file, bukan hanya yang terakhir

11

Saya ingin menambahkan header ke file dengan gema, kemudian gunakan perintah untuk membuat sisa file. Ini berarti saya akan menggunakan dua perintah terpisah.

Bagaimana cara menulis output dari kedua perintah ke file dengan pengalihan?

Saya sudah mencoba

echo "header line" | cut -c 1-5 input_file > output_file

echo "header line"; cut -c 1-5 input_file > output_file

Ini hanya mengarahkan output dari perintah cut.

Perintah berikut ini berfungsi, tetapi terasa canggung:

echo "header line" > output_file; cut -c 1-5 input_file >> output_file

Apa cara cerdas untuk menyelesaikan masalah saya?

Kucing Unfun
sumber

Jawaban:

11

Masalahnya di sini bukanlah masalah dengan redirection Linux; melainkan, itu adalah kesalahpahaman mendasar tentang cara kerja pipa. Pengalihan di sini tidak berfungsi karena hanya cut yang benar-benar mencetak ke stdout. stdout untuk perintah echo telah disalurkan ke stdin cut (yang tidak digunakan dalam kasus ini sejak file ditentukan).

echo "header line" > output_file && cut -c 1-5 input_file >> output_file

adalah apa yang Anda inginkan, dan tidak tidak berlaku sama sekali (saya mengganti Anda ;dengan &&sehingga perintah cut hanya akan mengeksekusi jika header berhasil ditulis; cara ini tidak akan dijalankan jika Anda tidak memiliki izin untuk membuat atau menulis ke output_file ).

Anda juga bisa melakukan semuanya dalam subkulit, mis.

(echo "header line"; cut -c 1-5 input_file) > output_file

tetapi tidak ada manfaat nyata untuk melakukan ini dan dengan contoh yang lebih kompleks dapat menyebabkan masalah jika Anda tidak terbiasa dengan bagaimana subkulit tersebut dicakup.

Jika Anda ingin memotong untuk melewati stdin hingga stdout Anda bisa mencoba:

echo "header line" | cut -c 1-5 - input_file

(Tanda hubung adalah jalan pintas umum untuk stdin)

Namun, ini juga akan melakukan operasi cut pada stdin (menghasilkan baris header "header"). Sulit untuk mengatakan apakah ini yang Anda inginkan atau tidak dari pertanyaan.

Sam Whited
sumber
13

Yang Anda cari adalah:

{ echo "header line"; cut -c 1-5 input_file; } > output_file
  • Sintaks ini tidak memiliki efek samping karena perintah dijalankan di shell saat ini, bukan subkulit
  • Ada batas yang jelas dari perintah yang menuju ke output_file
  • Ini berskala dengan baik karena Anda dapat menulis ulang seperti itu:

{
  echo "header line"
  cut -c 1-5 input_file
  ... # insert new commands here
} > output_file

Jika Anda ingin output kesalahan untuk pergi ke file yang sama, Anda dapat memodifikasi baris terakhir seperti itu:

} > output_file 2>&1

Terima kasih kepada Olivier Dulac untuk mengingatkan tip itu.

Jika Anda ingin beberapa output di dalam blok pergi ke layar Anda, Anda dapat menggunakan sintaks itu:

{
  echo "header line"
  echo "this line doesn't go to output_file" > /dev/tty
  cut -c 1-5 input_file
} > output_file
Jlliagre
sumber
+1: lebih jelas dan mengidentifikasi dengan jelas apa yang diarahkan ke mana. Untuk mengarahkan segala sesuatu (termasuk error msg): { .... } > some_file 2>&1(akan "mengkritik" nama_file untuk tidak mengkritik, tapi append untuk itu sebaliknya, hanya mengubah. >Menjadi >>: { ... } >> some_file 2>&1)
Olivier Dulac
4

Hanya untuk melengkapi jawaban ada eksekutif.

exec > output_file
echo "header line"
cut -c 1-5 input_file
Hildred
sumber
+1: dalam skrip, sangat umum untuk menggunakan ini (kurang begitu pada baris perintah, karena hal-hal mulai membingungkan ^^)
Olivier Dulac
Bisakah seseorang menguraikan solusi ini? Saya dapat melihat apa yang dilakukannya, tetapi saya tidak mengerti 'eksekutif' dalam konteks ini. Selain itu, sepertinya Anda harus mematikan lagi jika sisa skrip Anda memerlukan stdout normal.
Joe
1
Ketika Anda menggunakan exec dalam skrip tanpa perintah, Anda bisa melakukan I / O redirection pada exec yang mempengaruhi shell saat ini dan semua anak di masa depan.
Hildred
Terima kasih. Saya belum pernah melihat itu sebelumnya. Saya pikir ini akan sangat berguna.
Joe