Compress working directory - bash

I want to know the best way to compress the current working directory so that only the last directory's full name is visible. Let me give an example:
$ echo $PWD
/Users/mac/workshop/project1/src
I want to be able to pipe it through a series of commands such that I should get
~/w/p/src
I can obtain the first part of getting the leading ~ by doing ${PWD/#$HOME/\~}
$ echo ${PWD/#$HOME/\~}
~/workshop/project1/src
What do I pipe the rest through so that I get
$ echo ${PWD/#$HOME/\~} | ...
~/w/p/src

echo ${PWD/#$HOME/\~} |
sed -e 's%/\([^/]\)[^/]\{1,\}/%/\1/%g' \
-e 's%/\([^/]\)[^/]\{1,\}/%/\1/%g'
The repeated regex is necessary because the pattern matches, for example, the /src/ in ~/src/perl/DBD/Informix/lib/DBD/Informix, and the matching resumes with the p of perl, which isn't a slash, so it doesn't match immediately. You can see what happens by replacing the g with gp.
Example:
$ echo $PWD
/Users/jleffler/src/perl/DBD-Informix/lib/DBD/Informix
$ echo ${PWD/#$HOME/\~} |
> sed -e 's%/\([^/]\)[^/]\{1,\}/%/\1/%g' -e 's%/\([^/]\)[^/]\{1,\}/%/\1/%g'
~/s/p/D/l/D/Informix
$
$ echo ${PWD/#$HOME/\~} |
> sed -e 's%/\([^/]\)[^/]\{1,\}/%/\1/%gp' -e 's%/\([^/]\)[^/]\{1,\}/%/\1/%gp'
~/s/perl/D/lib/D/Informix
~/s/p/D/l/D/Informix
~/s/p/D/l/D/Informix
$

Command :
sed "s/\/home\/[^\/]*/~/;s_/\(.\)[^/]*_/\1_g" <<<"/home/ssam/Documents/so"
Output :
~/D/s
Command :
sed "s/\/home\/[^\/]*/~/;s_/\(.\)[^/]*_/\1_g" <<<"/homey/singo/Documents/so"
Output :
/h/s/D/s

Related

User input into variables and grep a file for pattern

H!
So I am trying to run a script which looks for a string pattern.
For example, from a file I want to find 2 words, located separately
"I like toast, toast is amazing. Bread is just toast before it was toasted."
I want to invoke it from the command line using something like this:
./myscript.sh myfile.txt "toast bread"
My code so far:
text_file=$1
keyword_first=$2
keyword_second=$3
find_keyword=$(cat $text_file | grep -w "$keyword_first""$keyword_second" )
echo $find_keyword
i have tried a few different ways. Directly from the command line I can make it run using:
cat myfile.txt | grep -E 'toast|bread'
I'm trying to put the user input into variables and use the variables to grep the file
You seem to be looking simply for
grep -E "$2|$3" "$1"
What works on the command line will also work in a script, though you will need to switch to double quotes for the shell to replace variables inside the quotes.
In this case, the -E option can be replaced with multiple -e options, too.
grep -e "$2" -e "$3" "$1"
You can pipe to grep twice:
find_keyword=$(cat $text_file | grep -w "$keyword_first" | grep -w "$keyword_second")
Note that your search word "bread" is not found because the string contains the uppercase "Bread". If you want to find the words regardless of this, you should use the case-insensitive option -i for grep:
find_keyword=$(cat $text_file | grep -w -i "$keyword_first" | grep -w -i "$keyword_second")
In a full script:
#!/bin/bash
#
# usage: ./myscript.sh myfile.txt "toast" "bread"
text_file=$1
keyword_first=$2
keyword_second=$3
find_keyword=$(cat $text_file | grep -w -i "$keyword_first" | grep -w -i "$keyword_second")
echo $find_keyword

How to replace '/' with '/\' using sed in shell scripting

I am trying to replace
prakash/annam/DevOps ---> prakash/\annam/\Devops
I am using this:
sed "s/'[//]''///\\/g"
Unfortunately, it is not giving the required output can anyone please help with this!!!
you can use a separator other than slash:
$ sed 's#/#\\/#g' <<< "a/b/c"
a\/b\/c
$ sed 's#/#/\\#g' <<< "a/b/c"
a/\b/\c
You can use sed with -i flag to place in place changes to the file
*nix
$ cat test
prakash/annam/DevOps
$ sed -i 's/\//\/\\/g' test
$ cat test
prakash/\annam/\DevOps
MacOS
$ cat test
prakash/annam/DevOps
$ sed -i '' 's/\//\/\\/g' test
$ cat test
prakash/\annam/\DevOps
Use
sed -E 's/\//\/\\/g'
e.g.
$ echo "prakash/annam/DevOps" | sed -E 's/\//\/\\/g'
prakash/\annam/\DevOps

How to decode \u003d escape in bash?

I have some strings like:
dimension\u003d1920x1024:format\u003djpg
In a file. I want to decode them so they will look like:
dimension=1920x1024:format=jpg
I know that:
$ echo -e dimension\u003d1920x1024:format\u003djpg
dimensionu003d1920x1024:formatu003djpg
$ echo -e 'dimension\u003d1920x1024:format\u003djpg'
dimension=1920x1024:format=jpg
$ echo -e "dimension\u003d1920x1024:format\u003djpg"
dimension=1920x1024:format=jpg
So I tried this to get what I want:
$ cat file | xargs -L1 echo -e
dimensionu003d1920x1024:formatu003djpg
But as you can see it doesn't work. How can I get this to work? How can I make xargs pass parameters to echo as if they were quoted?
You are actually asking how to convert the sequence \uXXXX into the corresponding Unicode code point. That's quite different from other backslash escapes, or handling backslashes in general. Neither echo -e nor xargs is particularly suited for this task.
Here is one way:
perl -CSD -pe 's/\\u(\X{4})/chr(oct("0x$1"))/ge' <<<"string"
Obscurely, oct("0xff") actually performs hex decoding, because of the "0x" prefix.
Obviously, if your input is the text in a file rather than just a string in the shell, simply pass that as the argument to Perl.
For small files:
Bash:
cat file | echo -e "$(cat -)"
Zsh:
cat file | { echo -e "$(cat -)"; }
For large files in both bash and zsh:
cat file | while read -r LINE; do echo -e "$LINE"; done
(loses spaces at the beginning of the line)
This is a try with ruby where the changes are written to the file
$ cat ./file
dimension\u003d1920x1024:format\u003djpg
dimension=800x600:format\u003djpg
The example above is made a bit more real-world.
$ cat ./script.rb
#!/usr/bin/ruby
contents=File.read("#{ARGV[0]}")
file=File.open("#{ARGV[0]}","w")
if file
file.syswrite(contents.gsub(/\\[uU]\{?([0-9A-F]{4})\}?/i) { $1.hex.chr(Encoding::UTF_8) })
file.close()
else
puts "No file with name #{ARGV[0]} present, Usage script <filename>"
end
$ ./script file
# The changes are written to the file with nothing printed to stdout
$ cat ./file
dimension=1920x1024:format=jpg
dimension=800x600:format=jpg

How to get only matching part of a string?

I know how to use the utility sed in bash, and grep is also good. But for the output, they always output a line containing the pattern.
Is there a way in bash to cut out a particular string containing the pattern I want (using regexp)?
That's why you have --help flag, grep --help:
-o, --only-matching show only the part of a line matching PATTERN
Now you can
$ echo 'hello world' | grep -o hello
hello
Using sed:
$ echo "hello world" | sed 's/.*\(hello\).*/\1/'
With GNU grep you can use -o:
-o Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.
Example:
$ echo ab cd ef gh | grep a
ab cd ef gh
$ echo ab cd ef gh | grep -o a
a
Through sed,
$ echo 'hello world' | sed 's/\(hello\)\|./\1/g'
hello
$ echo 'hello world' | sed -r 's/(hello)|./\1/g'
hello

How to compose custom command-line argument from file lines?

I know about the xargs utility, which allows me to convert lines into multiple arguments, like this:
echo -e "a\nb\nc\n" | xargs
Results in:
a b c
But I want to get:
a:b:c
The character : is used for an example. I want to be able to insert any separator between lines to get a single argument. How can I do it?
If you have a file with multiple lines than you want to change to a single argument changing the NEWLINES by a single character, the paste command is what you need:
$ echo -en "a\nb\nc\n" | paste -s -d ":"
a:b:c
Then, your command becomes:
your_command "$(paste -s -d ":" your_file)"
EDIT:
If you want to insert more than a single character as a separator, you could use sed before paste:
your_command "$(sed -e '2,$s/^/<you_separator>/' your_file | paste -s -d "")"
Or use a single more complicated sed:
your_command "$(sed -n -e '1h;2,$H;${x;s/\n/<you_separator>/gp}' your_file)"
The example you gave is not working for me. You would need:
echo -e "a\nb\nc\n" | xargs
to get a b c.
Coming back to your need, you could do this:
echo "a b c" | awk 'OFS=":" {print $1, $2, $3}'
it will change the separator from space to : or whatever you want it to be.
You can also use sed:
echo "a b c" | sed -e 's/ /:/g
that will output a:b:c.
After all these data processing, you can use xargs to perform the command you want to. Just | xargs and do whatever you want.
Hope it helps.
You can join the lines using xargs and then replace the space(' ' ) using sed.
echo -e "a\nb\nc"|xargs| sed -e 's/ /:/g'
will result in
a:b:c
obviously you can use this output as argument for other command using another xargs.
echo -e "a\nb\nc"|xargs| sed -e 's/ /:/g'|xargs

Resources