Bagaimana cara menghapus spasi putih tertinggal dengan sed?

113

Saya memiliki skrip shell sederhana yang menghapus spasi kosong dari file. Apakah ada cara untuk membuat skrip ini lebih ringkas (tanpa membuat file sementara)?

sed 's/[ \t]*$//' $1 > $1__.tmp
cat $1__.tmp > $1
rm $1__.tmp
Viktor
sumber
2
Anda dapat menggunakan mvsebagai pengganti catdan rm. Kenapa kamu tetap menggunakan catseperti itu? Mengapa tidak digunakan cp?
Dijeda sampai pemberitahuan lebih lanjut.
1
Saya menggunakan pengetahuan yang saya pelajari dari pertanyaan ini untuk membuat skrip shell untuk secara rekursif menghapus spasi kosong .
David Tuite
1
Solusi Anda sebenarnya lebih baik saat menggunakan MinGW karena bug yang ada di Windows: stackoverflow.com/questions/14313318/…
Cody Piersall
Perhatikan bahwa menggunakan catuntuk menimpa file asli daripada mvbenar-benar akan menggantikan data dalam file asli (yaitu, itu tidak akan merusak tautan keras). Menggunakan sed -iseperti yang diusulkan dalam banyak solusi tidak akan berhasil. IOW, terus lakukan apa yang Anda lakukan.
William Pursell

Jawaban:

157

Anda dapat menggunakan dalam pilihan tempat -idari seduntuk Linux dan Unix:

sed -i 's/[ \t]*$//' "$1"

Sadarilah ekspresi akan menghapus jejak tdi OSX (Anda dapat menggunakan gseduntuk menghindari masalah ini). Mungkin juga menghapusnya di BSD.

Jika Anda tidak memiliki gsed, berikut adalah sintaks sed yang benar (tetapi sulit dibaca) di OSX:

sed -i '' -E 's/[ '$'\t'']+$//' "$1"

Tiga string yang dikutip tunggal akhirnya digabungkan menjadi satu argumen / ekspresi. Tidak ada operator penggabungan dalam bash, Anda cukup menempatkan string satu demi satu tanpa spasi di antaranya.

The $'\t'resolve sebagai tab-karakter literal di bash (menggunakan ANSI-C mengutip ), sehingga tab dengan benar rubah menjadi ekspresi.

codaddict
sumber
1
Saya mendapatkan yang berikut di komputer saya yang tidak dapat saya perbarui: sed: Not a recognized flag: i
javaPlease42
2
hm. ini juga buggy dalam arti akan menghapus semua "t" yang tertinggal :)
Good Person
2
"sed: Bukan flag yang dikenali: i -" Ini terjadi di OSX. Anda perlu menambahkan ekstensi untuk file cadangan setelah -i di Mac. misalnya: sed -i .bak 's / [\ t] * $ //' $ 1
Aimon Bustardo
1
@GoodPerson Jika Anda tidak bercanda, Anda mungkin lupa untuk keluar dari t:) \tadalah tab, bagi mereka yang mungkin belum tahu.
Sean Allred
2
@SeanAllred tidak bercanda: benar-benar rusak kecuali jika Anda kebetulan menggunakan GNU sed (yang rusak dalam banyak hal lain)
Orang Baik
59

Setidaknya di Mountain Lion, jawaban Viktor juga akan menghilangkan karakter 't' saat berada di akhir baris. Perbaikan berikut ini mengatasi masalah tersebut:

sed -i '' -e's/[[:space:]]*$//' "$1"
acrollet
sumber
1
Sed saya juga ingin -Emenunjukkan "ekspresi reguler (modern) yang diperluas"
Jared Beck
Bekerja seperti pesona di OS X. Terima kasih banyak.
jww
1
Jawaban codaddict memiliki masalah yang sama di OS X (sekarang macOS). Ini adalah satu-satunya solusi di platform ini.
Franklin Yu
@JaredBeck Tambang seddi El Capitan tidak.
Franklin Yu
19

Terima kasih kepada codaddict karena telah menyarankan -iopsi.

Perintah berikut memecahkan masalah di Snow Leopard

sed -i '' -e's/[ \t]*$//' "$1"
Viktor
sumber
7
Seperti yang dikatakan @acrollet, Anda tidak dapat menggunakan \tsed selain GNU sed dan itu akan ditafsirkan sebagai huruf literal t. Perintah hanya tampak berfungsi, mungkin karena tidak ada TAB di spasi kosong atau tdi akhir kalimat di file Anda. ''Tidak disarankan menggunakan tanpa menentukan sufiks cadangan.
Scrutinizer
13

Yang terbaik adalah mengutip $ 1:

sed -i.bak 's/[[:blank:]]*$//' "$1"
Scrutinizer
sumber
5
var1="\t\t Test String trimming   "
echo $var1
Var2=$(echo "${var1}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
echo $Var2
Sandip Patel - SM
sumber
1
Hei, itulah yang kubutuhkan! Solusi sed lain yang diposting memiliki masalah integrasi dengan tugas variabel piped (dan piped and piped ...) di skrip bash saya, tetapi milik Anda berhasil di luar kotak.
Eric L.
4

Saya memiliki skrip di .bashrc saya yang bekerja di bawah OSX dan Linux (hanya bash!)

function trim_trailing_space() {
  if [[ $# -eq 0 ]]; then
    echo "$FUNCNAME will trim (in place) trailing spaces in the given file (remove unwanted spaces at end of lines)"
    echo "Usage :"
    echo "$FUNCNAME file"
    return
  fi
  local file=$1
  unamestr=$(uname)
  if [[ $unamestr == 'Darwin' ]]; then
    #specific case for Mac OSX
    sed -E -i ''  's/[[:space:]]*$//' $file
  else
    sed -i  's/[[:space:]]*$//' $file
  fi
}

yang saya tambahkan:

SRC_FILES_EXTENSIONS="js|ts|cpp|c|h|hpp|php|py|sh|cs|sql|json|ini|xml|conf"

function find_source_files() {
  if [[ $# -eq 0 ]]; then
    echo "$FUNCNAME will list sources files (having extensions $SRC_FILES_EXTENSIONS)"
    echo "Usage :"
    echo "$FUNCNAME folder"
    return
  fi
  local folder=$1

  unamestr=$(uname)
  if [[ $unamestr == 'Darwin' ]]; then
    #specific case for Mac OSX
    find -E $folder -iregex '.*\.('$SRC_FILES_EXTENSIONS')'
  else
    #Rhahhh, lovely
    local extensions_escaped=$(echo $SRC_FILES_EXTENSIONS | sed s/\|/\\\\\|/g)
    #echo "extensions_escaped:$extensions_escaped"
    find $folder -iregex '.*\.\('$extensions_escaped'\)$'
  fi
}

function trim_trailing_space_all_source_files() {
  for f in $(find_source_files .); do trim_trailing_space $f;done
}
Pascal T.
sumber
3

Bagi mereka yang mencari efisiensi (banyak file untuk diproses, atau file besar), menggunakan +operator pengulangan alih-alih *membuat perintah lebih dari dua kali lebih cepat.

Dengan GNU sed:

sed -Ei 's/[ \t]+$//' "$1"
sed -i 's/[ \t]\+$//' "$1"   # The same without extended regex

Saya juga dengan cepat membandingkan sesuatu yang lain: menggunakan [ \t]alih-alih [[:space:]]juga secara signifikan mempercepat proses (GNU sed v4.4):

sed -Ei 's/[ \t]+$//' "$1"

real    0m0,335s
user    0m0,133s
sys 0m0,193s

sed -Ei 's/[[:space:]]+$//' "$1"

real    0m0,838s
user    0m0,630s
sys 0m0,207s

sed -Ei 's/[ \t]*$//' "$1"

real    0m0,882s
user    0m0,657s
sys 0m0,227s

sed -Ei 's/[[:space:]]*$//' "$1"

real    0m1,711s
user    0m1,423s
sys 0m0,283s
yolenoyer
sumber
1

Hanya untuk bersenang-senang:

#!/bin/bash

FILE=$1

if [[ -z $FILE ]]; then
   echo "You must pass a filename -- exiting" >&2
   exit 1
fi

if [[ ! -f $FILE ]]; then
   echo "There is not file '$FILE' here -- exiting" >&2
   exit 1
fi

BEFORE=`wc -c "$FILE" | cut --delimiter=' ' --fields=1`

# >>>>>>>>>>
sed -i.bak -e's/[ \t]*$//' "$FILE"
# <<<<<<<<<<

AFTER=`wc -c "$FILE" | cut --delimiter=' ' --fields=1`

if [[ $? != 0 ]]; then
   echo "Some error occurred" >&2
else
   echo "Filtered '$FILE' from $BEFORE characters to $AFTER characters"
fi
David Tonhofer
sumber
0

Dalam kasus khusus sed, -iopsi yang telah disebutkan orang lain adalah yang paling sederhana dan paling waras.

Dalam kasus yang lebih umum sponge, dari moreutilscollection, melakukan apa yang Anda inginkan: ini memungkinkan Anda mengganti file dengan hasil pemrosesannya, dengan cara yang dirancang khusus untuk menjaga langkah pemrosesan agar tidak tersandung sendiri dengan menimpa file itu sendiri. bekerja pada. Mengutip spongehalaman manual:

sponge membaca input standar dan menuliskannya ke file yang ditentukan. Tidak seperti shell redirect, spons menyerap semua masukannya sebelum menulis file keluaran. Hal ini memungkinkan pembuatan pipeline yang membaca dari dan menulis ke file yang sama.

https://joeyh.name/code/moreutils/

Dan Martinez
sumber
-1

Untuk hanya menghapus spasi putih (dalam kasus saya spasi dan tab) dari baris dengan setidaknya satu karakter non-spasi (dengan cara ini baris kosong tidak disentuh):

sed -i -r 's/([^ \t]+)[ \t]+$/\1/' "$file"
phk
sumber