Làm thế nào để loại bỏ khoảng trắng ở cuối với sed?


113

Tôi có một tập lệnh shell đơn giản để loại bỏ khoảng trắng theo sau khỏi tệp. Có cách nào để làm cho tập lệnh này nhỏ gọn hơn (mà không cần tạo tệp tạm thời) không?

sed 's/[ \t]*$//' $1 > $1__.tmp
cat $1__.tmp > $1
rm $1__.tmp

2
Bạn có thể sử dụng mvthay thế cho catrm. Tại sao bạn vẫn sử dụng catnhư vậy anyway? Tại sao không sử dụng cp?
Tạm dừng cho đến khi có thông báo mới.

1
Tôi đã sử dụng kiến ​​thức tôi học được từ câu hỏi này để tạo một tập lệnh shell để loại bỏ một cách đệ quy khoảng trắng theo sau .
David Tuite

1
Giải pháp của bạn là thực sự tốt hơn khi sử dụng MinGW do một lỗi trong sed trên Windows: stackoverflow.com/questions/14313318/...
Cody Piersall


Lưu ý rằng việc sử dụng catđể ghi đè lên tệp gốc thay vì mvthực sự sẽ thay thế dữ liệu trong tệp gốc (tức là nó sẽ không phá vỡ các liên kết cứng). Sử dụng sed -inhư được đề xuất trong nhiều giải pháp sẽ không làm được điều đó. IOW, chỉ cần tiếp tục làm những gì bạn đang làm.
William Pursell

Câu trả lời:


157

Bạn có thể sử dụng tùy chọn tại chỗ -icủa sedLinux và Unix:

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

Lưu ý rằng biểu thức sẽ xóa dấu vết ttrên OSX (bạn có thể sử dụng gsedđể tránh sự cố này). Nó cũng có thể xóa chúng trên BSD.

Nếu bạn chưa có gsed, đây là cú pháp sed chính xác (nhưng khó đọc) trên OSX:

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

Ba chuỗi được trích dẫn đơn cuối cùng được nối thành một đối số / biểu thức duy nhất. Không có toán tử nối trong bash, bạn chỉ cần đặt lần lượt các chuỗi mà không có khoảng trống ở giữa.

Giải $'\t'quyết dưới dạng một ký tự tab theo nghĩa đen trong bash (sử dụng trích dẫn ANSI-C ), vì vậy tab được nối chính xác vào biểu thức.


1
Tôi nhận được thông tin sau trên máy của mình mà tôi không thể cập nhật: sed: Not a recognized flag: i
javaPlease42

2
hm. nó cũng có lỗi theo nghĩa là nó sẽ xóa tất cả các chữ "t" ở cuối :)
Good Person

2
"sed: Không phải là cờ được công nhận: i -" Điều này xảy ra trên OSX. Bạn cần thêm phần mở rộng cho tệp sao lưu sau -i trên máy Mac. ví dụ: sed -i .bak 's / [\ t] * $ //' $ 1
Aimon Bustardo

1
@GoodPerson Nếu bạn không đùa, bạn có thể quên thoát t:) \tlà một tab, dành cho những người có thể chưa biết.
Sean Allred

2
@SeanAllred không đùa đâu: nó hoàn toàn bị hỏng trừ khi bạn tình cờ sử dụng GNU sed (bị hỏng theo nhiều cách khác)
Good Person

59

Ít nhất ở Mountain Lion, câu trả lời của Viktor cũng sẽ xóa ký tự 't' khi nó ở cuối dòng. Các cách sau khắc phục sự cố đó:

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

1
My sed cũng muốn có một -Echỉ "mở rộng (hiện đại) biểu thức thông thường"
Jared Beck

Hoạt động như một sự quyến rũ trên OS X. Cảm ơn bạn rất nhiều.
jww

1
Câu trả lời của codaddict có vấn đề tương tự trên OS X (bây giờ là macOS). Đây là giải pháp duy nhất trên nền tảng này.
Franklin Yu,

@JaredBeck Mine sedtrên El Capitan thì không.
Franklin Yu,

19

Cảm ơn codaddict đã đề xuất -itùy chọn.

Lệnh sau giải quyết sự cố trên Snow Leopard

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


7
Giống như @acrollet đã nói, bạn không thể sử dụng \tvới sed ngoài GNU sed và nó được hiểu là một chữ cái theo nghĩa đen t. Lệnh này dường như chỉ hoạt động, có thể là do không có TAB trong khoảng trắng tở cuối cũng như không có ở cuối câu trong tệp của bạn. Không nên sử dụng ''mà không chỉ định hậu tố sao lưu.
soi

13

Tốt nhất là cũng nên báo giá $ 1:

sed -i.bak 's/[[:blank:]]*$//' "$1"

5
var1="\t\t Test String trimming   "
echo $var1
Var2=$(echo "${var1}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
echo $Var2

1
Này, đó chỉ là những gì tôi cần! Các giải pháp sed khác được đăng đã gặp sự cố khi tích hợp với phân công biến đường ống (và đường ống và đường ống ...) trong tập lệnh bash của tôi, nhưng của bạn đã hoạt động không hiệu quả.
Eric L.

4

Tôi có một tập lệnh trong .bashrc của mình hoạt động trên OSX và Linux (chỉ 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
}

mà tôi thêm vào:

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
}

3

Đối với những người tìm kiếm hiệu quả (nhiều tệp để xử lý hoặc tệp lớn), sử dụng +toán tử lặp lại thay vì* làm cho lệnh nhanh hơn gấp đôi.

Với GNU sed:

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

Tôi cũng nhanh chóng đánh giá một thứ khác: sử dụng [ \t]thay vì [[:space:]]cũng tăng tốc đáng kể quá trình (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

1

Chỉ cho vui thôi:

#!/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

0

Trong trường hợp cụ thể của sed,-i tùy chọn mà những người khác đã đề cập đến là lựa chọn đơn giản và an toàn nhất.

Trong trường hợp chung hơn sponge, từ moreutilsbộ sưu tập, thực hiện chính xác những gì bạn muốn: nó cho phép bạn thay thế một tệp bằng kết quả xử lý nó, theo cách được thiết kế đặc biệt để giữ cho bước xử lý không bị vấp ngã bằng cách ghi đè lên chính tệp của nó. cải tiến. Để trích dẫn spongetrang người đàn ông:

bọt biển đọc đầu vào tiêu chuẩn và ghi nó ra tệp được chỉ định. Không giống như chuyển hướng shell, bọt biển thấm tất cả đầu vào của nó trước khi ghi tệp đầu ra. Điều này cho phép xây dựng các đường ống đọc và ghi vào cùng một tệp.

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


-1

Để chỉ tách các khoảng trắng (trong trường hợp của tôi là khoảng trắng và tab) khỏi các dòng có ít nhất một ký tự không phải khoảng trắng (theo cách này, các dòng trống thụt vào không được chạm vào):

sed -i -r 's/([^ \t]+)[ \t]+$/\1/' "$file"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.