Unix - Нужно вырезать файл с несколькими пробелами в качестве разделителя - awk или cut? - PullRequest
10 голосов
/ 06 декабря 2010

Мне нужно получить записи из текстового файла в Unix. Разделителем является несколько пробелов. Например:

2U2133   1239  
1290fsdsf   3234

Из этого мне нужно извлечь

1239  
3234

Разделителем для всех записей всегда будет 3 пробела.

Мне нужно сделать это в сценарии Unix (.scr) и записать вывод в другой файл или использовать его в качестве входных данных для цикла do-while. Я попробовал следующее:

while read readline  
do  
        read_int=`echo "$readline"`  
        cnt_exc=`grep "$read_int" ${Directory path}/file1.txt| wc -l`  
if [ $cnt_exc -gt 0 ]  
then  
  int_1=0  
else  
  int_2=0  
fi  
done < awk -F'  ' '{ print $2 }' ${Directoty path}/test_file.txt  

test_file.txt - это входной файл, а file1.txt - это файл поиска. Но вышеприведенный способ не работает и выдает синтаксические ошибки рядом с awk -F

Я попытался записать вывод в файл. В командной строке работали:

more test_file.txt | awk -F'   ' '{ print $2 }' > output.txt

Это работает и записывает записи в файл output.txt в командной строке. Но та же команда не работает в сценарии unix (это файл .scr)

Пожалуйста, дайте мне знать, где я иду не так и как я могу решить эту проблему.

Спасибо
Visakh

Ответы [ 8 ]

23 голосов
/ 10 июня 2013
cat <file_name> | tr -s ' ' | cut -d ' ' -f 2
11 голосов
/ 06 декабря 2010

Это зависит от версии или реализации cut на вашей машине. Некоторые версии поддерживают опцию, обычно -i, которая означает «игнорировать пустые поля» или, что эквивалентно, допускает использование нескольких разделителей между полями. Если это поддерживается, используйте:

cut -i -d' ' -f 2 data.file

Если нет (и это не универсально - и, возможно, даже не распространено, поскольку ни GNU, ни MacOS X не имеют такой возможности), то использование awk лучше и более переносимо.

Вам нужно направить вывод awk в ваш цикл, хотя:

awk -F' ' '{print $2}' ${Directory_path}/test_file.txt |
while read readline  
do  
    read_int=`echo "$readline"`  
    cnt_exc=`grep "$read_int" ${Directory_path}/file1.txt| wc -l`  
    if [ $cnt_exc -gt 0 ]  
    then int_1=0  
    else int_2=0
    fi  
done

Единственная остаточная проблема заключается в том, находится ли цикл while в под-оболочке и, следовательно, не изменяет ли переменные ваших основных сценариев оболочки, а только свою собственную копию этих переменных.

С bash вы можете использовать процесс подстановки :

while read readline  
do  
    read_int=`echo "$readline"`  
    cnt_exc=`grep "$read_int" ${Directory_path}/file1.txt| wc -l`  
    if [ $cnt_exc -gt 0 ]  
    then int_1=0  
    else int_2=0
    fi  
done < <(awk -F' ' '{print $2}' ${Directory_path}/test_file.txt)

Это оставляет цикл while в текущей оболочке, но обеспечивает вывод команды, как будто из файла.

Пробел в ${Directory path} обычно недопустим - если только это не другая функция Bash, которую я пропустил; у вас также была опечатка (Directoty) в одном месте.

3 голосов
/ 06 декабря 2010

Кроме других способов сделать то же самое, ошибка в вашей программе заключается в следующем: вы не можете перенаправить (<) вывод другой программы.Переверните ваш сценарий и используйте конвейер, подобный этому:

awk -F'   ' '{ print $2 }' ${Directory path}/test_file.txt | while read readline

и т. Д.

Кроме того, использование readline в качестве имени переменной может вызывать или не создавать проблемы.

2 голосов
/ 19 января 2012

В этом конкретном случае вы можете использовать следующую строку

sed 's/   /\t/g' <file_name> | cut -f 2

, чтобы получить ваши вторые столбцы.

1 голос
/ 06 декабря 2010

В bash вы можете начать примерно так:

for n in `${Directoty path}/test_file.txt | cut -d " " -f 4`
{
    grep -c $n ${Directory path}/file*.txt
}
0 голосов
/ 26 марта 2019

Это должен был быть комментарий, но так как я пока не могу комментировать, я добавляю это здесь. Это отличный ответ здесь: https://stackoverflow.com/a/4483833/3138875

tr -s ' ' <text.txt | cut -d ' ' -f4

tr -s '<character>' сжимает несколько повторных экземпляров <character> в один.

0 голосов
/ 22 февраля 2016

Cut недостаточно гибок. Я обычно использую Perl для этого:

cat file.txt | perl -F'   ' -e 'print $F[1]."\n"'

Вместо тройного пробела после -F вы можете поместить любое регулярное выражение Perl. Доступ к полям осуществляется как $ F [n] , где n - номер поля (отсчет начинается с нуля). Таким образом, нет необходимости sed или tr .

0 голосов
/ 06 декабря 2010

Это не работает в скрипте из-за опечатки в "Directo * t * y path" (последняя строка вашего скрипта).

...