clipdel (2564B)
1 #!/usr/bin/env bash 2 3 : "${CM_DIR="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}" 4 CM_REAL_DELETE=0 5 if [[ $1 == -d ]]; then 6 CM_REAL_DELETE=1 7 shift 8 fi 9 10 major_version=6 11 12 shopt -s nullglob 13 14 cache_dir=$CM_DIR/clipmenu.$major_version.$USER 15 cache_file=$cache_dir/line_cache 16 lock_file=$cache_dir/lock 17 lock_timeout=2 18 19 if [[ $1 == --help ]] || [[ $1 == -h ]]; then 20 cat << 'EOF' 21 clipdel deletes clipmenu entries matching a regex. By default, just lists what 22 it would delete, pass -d to do it for real. If no pattern is passed as an argument, 23 it will try to read one from standard input. 24 25 ".*" is special, it will just nuke the entire data directory, including the 26 line caches and all other state. 27 28 Arguments: 29 30 -d Delete for real. 31 32 Environment variables: 33 34 - $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp) 35 EOF 36 exit 0 37 fi 38 39 if ! [[ -f $cache_file ]]; then 40 printf '%s\n' "No line cache file found, no clips exist" >&2 41 exit 0 # Well, this is a kind of success... 42 fi 43 44 if [[ -n $1 ]]; then 45 raw_pattern=$1 46 elif ! [[ -t 0 ]]; then 47 IFS= read -r raw_pattern 48 fi 49 50 esc_pattern=${raw_pattern//\#/'\#'} 51 52 # We use 2 separate sed commands so "esc_pattern" matches only the 'clip' text 53 # without the timestamp (e.g. $> clipdel '^delete_exact_match$') 54 sed_common_command="s#^[0-9]\+ ##;\\#${esc_pattern}#" 55 56 if ! [[ $raw_pattern ]]; then 57 printf '%s\n' 'No pattern provided, see --help' >&2 58 exit 2 59 fi 60 61 exec {lock_fd}> "$lock_file" 62 63 if (( CM_REAL_DELETE )) && [[ "$raw_pattern" == ".*" ]]; then 64 flock -x -w "$lock_timeout" "$lock_fd" || exit 65 rm -rf -- "$cache_dir" 66 mkdir -p -- "$cache_dir" 67 exit 0 68 else 69 mapfile -t matches < <( 70 sed -n "${sed_common_command}p" "$cache_file" | 71 sort -u 72 ) 73 74 if (( CM_REAL_DELETE )); then 75 flock -x -w "$lock_timeout" "$lock_fd" || exit 76 77 for match in "${matches[@]}"; do 78 ck=$(cksum <<< "$match") 79 rm -f -- "$cache_dir/$ck" 80 done 81 82 temp=$(mktemp) 83 # sed 'h' and 'g' here means save and restore the line, so 84 # timestamps are not removed from non-deleted lines. 'd' deletes the 85 # line and restarts, skipping 'g'/restore. 86 # https://www.gnu.org/software/sed/manual/html_node/Other-Commands.html#Other-Commands 87 sed "h;${sed_common_command}d;g" "$cache_file" > "$temp" 88 mv -- "$temp" "$cache_file" 89 90 flock -u "$lock_fd" 91 else 92 if (( ${#matches[@]} )); then 93 printf '%s\n' "${matches[@]}" 94 fi 95 fi 96 fi