Hot answers tagged

17

You can use cut to split files with columns on a specific delimiter: cut -d: -f6 /etc/passwd Or -f1,6 for columns (fields) 1 and 6.


13

Use the \ character to escape the * to make it a normal character. grep '^\*\*' test.out Also note the single quote ' and not double quote " to prevent the shell expanding things


9

Grep is really not the tool for parsing out data this way, grep is more for pattern matching and you're trying to do text-processing. You would want to use awk. awk -F":" '$7 == "/bin/false" {print "User: "$1 "Home Dir: "$6}' /etc/passwd awk The command -F":" Sets the data delimiter to : $7 == "/bin/false" Checks if the 7th data column is /bin/false {...


7

As you wanted to check the line which starts with ** and ends with ), you can combine two grep operation like this, grep '^*\*' test.out | grep ')$' Or with single grep command like this, grep -E '^\*\*.*\)$' test.out Explanation ^\*\* : match line which starts with ** .* : match everything after ** \)$ : match line which also has ) at the end of ...


7

One more way, assuming GNU find(1), just for fun: find $PWD -type f -name "file.txt" -printf '%p '


6

You can do this with an awk command most easily: your-command | awk -F\" -v OFS=. -v ORS=' ' '{print $2, $4, $6, $8}' To set it as a variable, use command substitution: myVariable="$(your-command | awk -F\" -v OFS=. -v ORS=' ' '{print $2, $4, $6, $8}')" -F sets the input field separator (which is by default any whitespace) to a custom value; in this ...


6

Someone might suggest a program. It is not a trivial problem to do well: "ANSI sequences" are standardized in ECMA-48, some of your examples (such as the cursor appearance and enter_ca_mode) are not in the standard, some such as the enter_ca_mode 1049 code have variations (\E7\E[?47h). If a program relies on a terminal description, only one of the ...


5

You can replace the LF character with a space using the 'tr' command tr '\012' ' ' < path.txt This can be part of the original command: find $PWD -type f -name "file.txt" | tr '\012' ' ' > paths.txt


5

Here's one way to do it with sed: sed '/PATTERN1/,$!d;/PATTERN2/{x;//{x;q;};g;}' infile This just deletes all lines (if any) up to the first occurrence of PATTERN1 and then, on each line that matches PATTERN2 it exchanges buffers. If the new pattern space also matches, it means it's the 2nd occurrence so it exchanges back and quits (after auto-printing). ...


4

You can use, paste too, find . -type f -name "path.txt" -exec paste -d' ' -s {} \; > path.txt


4

One simple way would be to pipe the find output through xargs (whose default action when no explicit command is given is to echo its arguments) find $PWD -type f -name "file.txt" | xargs > paths.txt Unlike simply replacing all the newlines with spaces, this preserves the final newline.


4

Assuming there's a file called dates containing the list of dates, one per line (and nothing else), something like this might work to count the ones older than 14 days: $ date=$(date --date="14 days ago" +%Y%m%d) $ awk '($0 < "'$date'") {count += 1} END {print count}' < dates 20 (Given they are in yyyymmdd format, the comparison is easy.)


4

The right tool for this job is pcregrep: pcregrep -M 'PATTERN1(.|\n)*PATTERN2' file where option -M allows pattern to match more than one line and (.|\n)* match any character or newline zero or more times. Notice that we took advantage of the greediness of the grep. If you would want to print form pattern1 up to the first occurrence of the pattern2, ...


4

Just use flags: $ awk '/PATTERN1/{flag=2;next} flag; /PATTERN2/{flag--}' file a b c PATTERN2 d e f PATTERN2 That is: when you find PATTERN1 set the flag to a positive value; in particular, 2. Then, when you find PATTERN2, decrease that flag in one. This way, it will exhaust after the second match. In between, use flag as a value that triggers the {print $...


3

You were on the right track to use awk. You should write a script that reads your logs, and outputs with the fields separated with tabs¹. Then use the column command to re-align the columns: extract.awk²: BEGIN {OFS="\t"; print "Timestamp\tEmailTo:\tEmailFrom:\tIPAddress:\tErrorCodes:"} {print $1, $6, $7, $NF, $(NF-5)} Then run it with this command: awk ...


3

Perhaps you meant to use less on the output of sed, rather than the reverse: sed -e 's/\(.*DATA.*\)/\o033[93m\1\o033[39m/' file | less -R Further reading: less - opposite of more


3

With gnu sed/shuf: sed '1b;s/^*/\x0*/' infile | shuf -zn 5 | tr -d '\000' This turns input into nul separated records i.e. on each line that starts with a * (except for the first one) it adds a nul char before the * then uses shuf with --zero-terminated switch to extract five random records and tr to delete those nul chars.


3

It's not the shell None of the answers so far has touched on the real problem. It would be helpful to explain why it does not work as you expect. grep -i "^**" test.out Because you have quoted the pattern to grep, * is not expanded by the shell. It is passed to grep as-is. This is explained in the manual page[1] for bash[2]: Enclosing characters in ...


3

To number lines, you may use nl. To remove columns (or rather filter out the ones you want to keep), you may use cut: $ cut -f 2- cols.txt | nl 1 0 chr1 3000575 3000801 0 chr1 4340023 4340249 32 32 2 0 chr1 3000641 3000801 -1 chr1 3311943 3311783 32 32 3 0 chr1 3000674 3000801 -1 ...


3

With awk $ awk '{$1=FNR-1; print}' OFS='\t' file 0 0 chr1 3000575 3000801 0 chr1 4340023 4340249 32 32 1 0 chr1 3000641 3000801 -1 chr1 3311943 3311783 32 32 2 0 chr1 3000674 3000801 -1 chr1 3001534 3001407 32 32 3 0 chr1 3000674 3000801 -1 chr1 3001534 3001407 32 32 4 0 chr1 3000674 3000801 -1 chr1 ...


3

awk is good for this, but you could do it simpler, with calcc() { awk "{\$$1=$2;print}" | column -t } Whether that's better or not is your choice.


2

If you want to use one of those tools you mentioned, you can do it with sed: echo "/Folder/F1/F2/F3/F4/.../Fn/abc.txt" | sed "s/\/[^/]*$//" sed -i "s/\/[^/]*$//" path.txt If you are in bash, you can use Bash parameter expansion for this: path=$(cat path.txt) echo "${path%/*}" And as mentioned by ikkachu you can use dirname.


2

basename and dirname print the last and all-but-last parts of a filename given as argument, so: $ dirname "/Folder/F1/F2/F3/F4/.../Fn/abc.txt" /Folder/F1/F2/F3/F4/.../Fn (or from a file: dirname "$(< pathname.txt)" )


2

You can also take advantage of the fact that the shell strips newlines from command substitutions. So, instead of find $PWD -type f -name "file.txt" > paths.txt, you can do (note that you don't need the $PWD, it is the default value for find): echo $(find $PWD -type f -name "file.txt") > paths.txt or printf '%s ' $(find $PWD -type f -name "file.txt"...


2

Here's one way to do it with sed: sed '/Os version rhel5\.6/{ a\ apache 4.2 $!{ n /^apache 4\.2$/d } }' infile This appends apache 4.2 unconditionally to all lines matching Os version rhel5.6 then (if not on the last line) it pulls in the next line via n (printing the pattern space) and if the new pattern space content matches apache 4.2 it deletes it. ...


2

This perl expression will do the trick, perl -i -ne 'next if /apache 4.2/;s+Os version rhel5.6+Os version rhel5.6\napache 4.2+; print' ssss Explanation next if /apache 4.2/ skips any lines matching apache 4.2. s+Os version rhel5.6+Os version rhel5.6\napache 4.2+; print search Os version rhel5.6 and replaces line with same with appending apache 4.2 at ...


2

You can accomplish this with awk awk '{sub(/".*",/,"");print}' filename


2

cat listfile | tr '\n' , | sed 's/,\*/\n*/g;s/,$//' | shuf | head -n 5 | tr , '\n'


2

That's quite simple: sed -i "s/\[ \]/[$(cat output.txt | xargs)]/" input.txt


2

Other options. You can use sed or awk also $ sed -n '/^*\*/p' test.out $ awk '/^*\*/' test.out To know lines that end with ) use also grep or sed or awk $ grep ')$' test.out $ sed -n '/)$/p' test.out $ awk '/)$/' test.out



Only top voted, non community-wiki answers of a minimum length are eligible